[
  {
    "path": ".gitattribute",
    "content": "*.bat text eol=crlf\n*.cmd text eol=crlf\n*.java text eol=lf\n*.scala text eol=lf\n*.xml text eol=lf\n*.py text eol=lf\n*.R text eol=lf\n# from apache spark\n\n*.sh text eol=lf\n* text eol=lf"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: CI\n\non: [push]\n\njobs:\n\n  vars:\n    runs-on: ubuntu-latest\n\n    outputs:\n      experimentalScalaVersions: \"\"\n\n    steps:\n      - name: dummy\n        run: echo dummy\n\n  build:\n    needs: vars\n    runs-on: ubuntu-latest\n\n    strategy: &scala_strategy\n      max-parallel: 2\n      fail-fast: false\n      matrix:\n        scalaVersion: [\"2.13.9\", \"2.13.10\", \"2.13.11\", \"2.13.12\", \"2.13.13\", \"2.13.14\", \"2.13.15\", \"2.13.16\", \"2.13.17\", \"2.13.18\"]\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up JDK 17\n        uses: actions/setup-java@v1\n        with:\n          java-version: 17\n      - name: Compile\n        run: ./dev/publishM2.sh -PscalaVersion=${{matrix.scalaVersion}}\n\n      - name: Pre-release on github\n        uses: \"marvinpinto/action-automatic-releases@latest\"\n        if: contains(github.ref_name, 'Release/')\n        with:\n          repo_token: \"${{ secrets.GITHUB_TOKEN }}\"\n          automatic_release_tag: \"${{github.ref_name}}-${{matrix.scalaVersion}}\"\n          title: \"${{github.ref_name}}-${{matrix.scalaVersion}}\"\n          prerelease: true\n          files: |\n            LICENSE\n            core/build/libs/*.jar\n\n  test:\n    needs: vars\n    runs-on: ubuntu-latest\n\n    #TODO: don't repeat yourself\n    strategy: *scala_strategy\n\n    continue-on-error: ${{ contains(needs.vars.outputs.experimentalScalaVersions, matrix.scalaVersion) }}\n\n    steps:\n      - name: debug vars\n        run: echo ${{ needs.vars.outputs.experimentalScalaVersions }}\n      - name: debug expression\n        run: echo ${{ job.continue-on-error }}\n      - uses: actions/checkout@v2\n      - name: Set up JDK 1.8\n        uses: actions/setup-java@v1\n        with:\n          java-version: 1.8\n      #         TODO: replica! how to remove?\n      - name: Test\n        run: ./dev/test.sh -PscalaVersion=${{matrix.scalaVersion}}\n      - name: Publish Unit Test Results\n        uses: EnricoMi/publish-unit-test-result-action@v1\n        if: always()\n        with:\n          files: |\n            **/test-results/test/*.xml\n          check_name: |\n            Test Report (${{matrix.scalaVersion}})\n"
  },
  {
    "path": ".gitignore",
    "content": "*.class\n*.log\nlogs\n\n# maven\n*.versionsBackup\n\n# gradle\n**/.gradle\n**/build\n**/bin\n\n# sbt\n.cache/\n.history/\n.lib/\ndist/*\ntarget/\nlib_managed/\nsrc_managed/\nproject/boot/\nproject/plugins/project/\n\n# Scala-IDE\n.scala_dependencies\n.worksheet\n\n# Eclipse\n.pmd\n.classpath\n.project\n.settings/\n\n# IntelliJ-IDEA\n*.iml\n.idea/\n.idea_modules/\n\n# VSCode\n.vscode/\n.obsidian/\n\n# BSP & Metals\n.bsp/\n.bloop/\n.metals/\n**/metals.sbt\n\n# the Singapore stack\n**/.ammonite/\n\n# Compiler\noutput\n*/target/\n\n#Misc\ntemp\n**/temp\nfoo\n\n#aws key\n**/rootkey.csv\n\n#publish\ndev/publish.sh"
  },
  {
    "path": ".scalafix.conf",
    "content": "runner.dialect = scala213\n\n// Built in rules\nrules = [\n  NoAutoTupling\t// Rewrite that inserts explicit tuples for adapted argument lists for compatibility with -Yno-adapted-args\n  NoValInForComprehension\n  ProcedureSyntax\n  RemoveUnused\n  LeakingImplicitClassVal\n  // TODO: unrealiable due to lack of speculative modification, disabled\n  //  ExplicitResultTypes\n]\n\nRemoveUnused {\n  imports = true\n  privates = true\n  locals = true\n  patternvars = true\n  params = true\n}\n\nExplicitResultTypes {\n  rewriteStructuralTypesToNamedSubclass = false\n  skipSimpleDefinitions = false\n}"
  },
  {
    "path": ".scalafmt.conf",
    "content": "version = \"3.7.14\"\nrunner.dialect = scala213\n\nmaxColumn = 120\nlineEndings = unix\n\n# Only format files tracked by git.\nproject.git = true\n\nalign {\n  preset = some\n  tokens = []\n}\n\ndocstrings {\n  blankFirstLine = true\n}\n\nnewlines {\n  #   topLevelStatements = [before]\n  sometimesBeforeColonInMethodReturnType = false\n  penalizeSingleSelectMultiArgList = false\n  beforeCurlyLambdaParams = multilineWithCaseOnly\n  # //  afterCurlyLambdaParams = squash\n  implicitParamListModifierForce = [before, after]\n}\n\nrewrite {\n  rules = [\n    # //    AvoidInfix,\n    Imports,\n    RedundantBraces,\n    RedundantParens,\n    SortModifiers\n  ]\n  imports {\n    sort=original\n  }\n  redundantBraces {\n    generalExpressions = false\n    methodBodies = false\n    includeUnitMethods = false\n    maxLines = 0\n  }\n}\n"
  },
  {
    "path": ".travis.yml",
    "content": "jdk:\n  - openjdk8\nlanguage: scala\nscript: 'sbt splain/test'\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Torsten Schmits\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# A scala compiler plugin for more concise errors\n\nThis plugin removes some of the redundancy of the compiler output and prints\nadditional info for implicit resolution errors.\n\n# Versions\n\nTL;DR\n\n```\n                 ┌──────────────────────────┐                  \n                 │What's your Scala version?│                  \n                 └─────────┬───────┬────────┘                  \n                           │       │                           \n                           │       └───────────────────┐       \n                           v                           │       \n    ┌─────────────────────────────────────────────┐    │       \n    │                ( >= 2.13.6 )                │    │       \n    │                ─────────────                │    │       \n    │Do you want experimental features & bugfixes?│    │       \n    └──┬───────────────┬──────────────────────────┘    │       \n       │               │                               │       \n       v               v                               v       \n ┌──────────┐ ┌─────────────────┐ ┌───────────────────────────┐\n │ ( yes )  │ │     ( no )      │ │( 2.12 / 2.13.0 .. 2.13.5 )│\n │ ───────  │ │     ──────      │ ├───────────────────────────┤\n │Splain 1.x│ │Compiler built-in│ │       Splain 0.5.x        │\n └──────────┘ └─────────────────┘ └───────────────────────────┘\n```\n\n### Compiler built-in\n\n(main article: https://docs.scala-lang.org/overviews/compiler-options/index.html#Verbose_Settings)\n\nThe basic Splain features has been integrated into Scala compiler (since 2.13.6, through contributions like [this](https://github.com/scala/scala/pull/7785) and [this](https://github.com/scala/scala/pull/10029)), they can be enabled immediately by using the right compiler options (see **Option** section for detail).\n\n### v1.x (master branch)\n\n(Only available for Scala 2.13.6+)\n\nSplain 1.x is a simplified rewrite that aims to incrementally introduce enhancement to the already integrated Splain features. Additional features and bugfixes will first be released and refined here, then be periodically contributed back into Scala compiler.\n\nEffectively, **Splain 1.x is now a feature preview patch of Scala compiler**, if a relevant compiler built-in option (see **Option** section for detail) malfunctions, it may work with Splain v1.x enabled.\n\nIt is also the only branch under active development.\n\n### v0.5.x (maintenance branch)\n\n(Only available for Scala 2.12 and Scala 2.13.0 .. 2.13.5)\n\nThe latest v0.x will continue to be maintained and published regularly to stay compatible with the latest Scala 2.12.x release (until it's end-of-life), but no newer version will be published for Scala 2.13, **splain 0.5.x will be the last release for Scala 2.13**.\n\nWe strongly recommend you to upgrade to Scala 2.13.6+ to benefit from active support and up-to-date features.\n\n### Build Matrix\n\n| Version                          | Status                                                                                                                                                            | Compatibility                                                                    |\n|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|\n| v1.x <br> (current) - latest     | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/tek/splain/actions/workflows/main.yml)               | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=master)  |\n| v1.1.0 <br> (current)            | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.1.0)](https://github.com/tek/splain/actions/workflows/main.yml)               | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.1.0)               |\n| v1.1.0-RC0 <br> (current)        | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.1.0-RC0)](https://github.com/tek/splain/actions/workflows/main.yml)    | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.1.0-RC0) |\n| v1.0.3 <br> (current)            | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.0.3)](https://github.com/tek/splain/actions/workflows/main.yml)        | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.0.3) |\n| v1.0.2 <br> (current)            | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.0.2)](https://github.com/tek/splain/actions/workflows/main.yml)        | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.0.2) |\n| v1.0.1 <br> (current)            | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.0.1)](https://github.com/tek/splain/actions/workflows/main.yml)        | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.0.1) |\n| v1.0.0 <br> (current)            | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.0.0)](https://github.com/tek/splain/actions/workflows/main.yml)        | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.0.0) |\n| v1.0.0-RC2 <br> (current)        | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.0.0-RC2)](https://github.com/tek/splain/actions/workflows/main.yml)    | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.0.0-RC2) |\n| v1.0.0-RC1 <br> (current)        | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Release/1.0.0-RC1)](https://github.com/tek/splain/actions/workflows/main.yml)    | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Release/1.0.0-RC1) |\n| v0.x <br> (maintenance) - latest | [![CI](https://github.com/tek/splain/actions/workflows/main.yml/badge.svg?branch=Maintenance%2Fmaster)](https://github.com/tek/splain/actions/workflows/main.yml) | ![badge](https://github-actions.40ants.com/tek/splain/matrix.svg?branch=Maintenance%2Fmaster) |\n\n# Usage\n\n### v1.x, v0.x\n\nInclude this line in your `build.sbt` (_not_ `project/plugins.sbt`!!):\n\n```sbt\naddCompilerPlugin(\"io.tryp\" % \"splain\" % \"0.5.8\" cross CrossVersion.patch)\n```\n\nIf you want to support scala versions both newer and older than `2.12.5`, use:\n\n```sbt\nlibraryDependencies += {\n  val v =\n    if (scalaVersion.value.replaceFirst(raw\"\\.(\\d)$$\",\".0$1\") <= \"2.12.04\") \"0.4.1\"\n    else \"0.5.8\"\n  (\"io.tryp\" %% \"splain\" % v cross CrossVersion.patch).withConfigurations(Some(\"plugin->default(compile)\"))\n}\n```\n\nIf you are using gradle with scala plugin, include this line under the dependency section of your build.gradle:\n\n```groovy\nscalaCompilerPlugins group: 'io.tryp', name: 'splain_${scalaVersion}', version: '0.5.8'\n```\n\nor build.gradle.kts:\n\n```kotlin\nscalaCompilerPlugins(\"io.tryp:splain_${scalaVersion}:0.5.8\")\n```\n\n### compiler built-in, no plugin declaration required\n\nIts effects however still have to be enabled in your compiler options, in minimal case, by the following 2 options (see Options for details):\n\n```\n-Vimplicits -Vtype-diffs\n```\n\n# Options\n\nThe plugin can be configured via compiler Options with the format:\n\n| v0.x                          | built-in, v1.x       |\n|:----------------------------- | -------------------- |\n| `-P:splain:<param>[:<value>]` | `-<param>[:<value>]` |\n\n`param` can be one of the following:\n\n| v0.x              | built-in, v1.x                            | default value    |\n| ----------------- |-------------------------------------------|------------------|\n| `all`             | `enabled`                                 | true             |\n| `infix`           | (dropped)                                 |                  |\n| `foundreq`        | `Vtype-diffs`                             | false            |\n| `implicits`       | `Vimplicits`                              | false            |\n| `bounds`          | (dropped)                                 | false            |\n| `color`           | (dropped)                                 |                  |\n| `breakinfix`      | (dropped)                                 | 0                |\n| `tree`            | `Vimplicits-verbose-tree`                 |                  |\n| `compact`         | (dropped)                                 | false            |\n| `boundsimplicits` | (dropped)                                 |                  |\n| `truncrefined`    | `Vimplicits-max-refined`                  | 0                |\n| `rewrite`         | (dropped)                                 | (do not rewrite) |\n| `keepmodules`     | (dropped)                                 | 0                |\n| (N/A)             | `P:splain:Vimplicits-diverging`           | false            |\n| (N/A)             | `P:splain:Vimplicits-diverging-max-depth` | 100              |\n| (N/A)             | `P:splain:Vtype-detail`                   | 1                |\n| (N/A)             | `P:splain:Vtype-diffs-detail`             | 1                |\n\n\n`value` can either be `true` or `false`. If omitted, the default is `true` for\nboth value and parameter.\n\nThe parameter `all` can be used to deactivate all features.\n\nThe parameters can be applied like this:\n\n(in sbt)\n\n```sbt\nscalacOptions += \"-P:splain:implicits:false\"\n```\n\n(in gradle with scala plugin)\n\n```kotlin\nwithType<ScalaCompile> {\n    scalaCompileOptions.apply {\n        additionalParameters = listOf(\"-P:splain:implicits:false\")\n    }\n}\n```\n\n# infix types\n\nInstead of `shapeless.::[A, HNil]`, prints `A :: HNil`.\n\n# found/required types\n\nRather than printing up to four types, only the dealiased types are shown as a colored diff:\n\n![foundreq](img/foundreq.jpg)\n\nspecial consideration for `shapeless.Record`:\n\n![foundreq_record](img/foundreq_record.jpg)\n\nIn the case of refined types in the form of `Client with Database with\nPublisher`, the types will be matched with each other and a missing or surplus\ntype will be indicated by a `<none>` label.\n\n# implicit resolution chains\n\nWhen an implicit is not found, only the outermost error at the invocation point\nis printed. This can be expanded with the compiler flag `-Xlog-implicits`, but\nthat also shows all invalid implicits for parameters that have been resolved\nsuccessfully.\nThis feature prints a compact list of all involved implicits:\n![implicits](img/implicits.jpg)\n\nHere, `!I` stands for *could not find implicit value*, the name of the implicit\nparameter is in yellow, and its type in green.\n\nIf the parameter `tree` is set, the candidates will be indented according to their nesting level:\n\n![tree](img/tree.jpg)\n\nIf the parameter `compact` is set, only the first and last implicit in a chain will be printed.\n\nIf the parameter `boundsimplicits` is set to false, any **nonconformant bounds** errors will be suppressed.\n\nFor comparison, this is the regular compiler output for this case (with\nformatted types):\n\n```\n[info] unit/src/basic.scala:35: f is not a valid implicit value for\nsplain.ImplicitChain.T2 because:\n[info] hasMatchingSymbol reported error: could not find implicit value for\nparameter impPar2: (D *** (C *** String)) >:< ((C,D,C) *** D)\n[info]   implicitly[T1]\n[info]             ^\n[info] unit/src/basic.scala:35: g is not a valid implicit value for\nsplain.ImplicitChain.T1 because:\n[info] hasMatchingSymbol reported error: could not find implicit value for\nparameter impPar1: D *** ((C >:< C) *** (D => Unit))\n[info]   implicitly[T1]\n[info]             ^\n[error] unit/src/basic.scala:35: could not find implicit value for\nparameter e: (C *** D) >:< C with D {type A = D; type B = C}\n[error]   implicitly[T1]\n```\n\n# infix type and type argument line breaking\n\nIf the parameter `breakinfix` is given and greater than 0, types longer than\nthat number will be split into multiple lines:\n\n```\nimplicit error;\n!I e: String\nf invalid because\n!I impPar4: List[\n  (\n    VeryLongTypeName ::::\n    VeryLongTypeName ::::\n    VeryLongTypeName ::::\n    VeryLongTypeName\n  )\n  ::::\n  (Short :::: Short) ::::\n  (\n    VeryLongTypeName ::::\n    VeryLongTypeName ::::\n    VeryLongTypeName ::::\n    VeryLongTypeName\n  )\n  ::::\n  VeryLongTypeName ::::\n  VeryLongTypeName ::::\n  VeryLongTypeName ::::\n  VeryLongTypeName\n]\n```\n\n# truncating refined types\n\nA type of the shape `T { type A = X; type B = Y }` will be displayed as `T {...}` if the parameter `truncrefined` is set\nto a value `/= 0` and the refinement's length is greater than the value.\n\n# truncating module paths\n\nDefault behaviour when printing type names is to omit the whole module path and only print the last segment.\nTwo options modify this behaviour:\n\n## regex rewrite\n\nThe option `rewrite` takes a string that is parsed as a `;`-delimited list of regexes and optional replacements.\n\nFor example:\n\n```\n-P:splain:rewrite:cats\\\\.data/cd;.Type\n```\n\nThis parses as two rewrite items:\n\n* transform `cats.data` into `cd`\n* delete all occurences of `.Type`\n\nIf a slash is present, the string following it will be used as a replacement for the matched text.\nIf it is absent, the empty string is substituted.\n\n## dropping module segments by count\n\nThe option `keepmodules` determines how many segments of the module path before the type name will be displayed, but\nonly if the `rewrite` mechanism hasn't changed anything.\n\nSo with `-P:splain:keepmodules:2`, the qualified type `cats.free.FreeT.Suspend` will be displayed as\n`free.FreeT.Suspend`, keeping the two segments `free.FreeT` before the type name.\nThe default is `0`, so only the type name itself will be displayed\n\n# expanding diverging implicit errors (experimental)\n\nA `diverging implicit error` is thrown by compiler if it cannot decide if an implicit search can terminate in polynomial time (e.g. if the search algorithm encounter a loop or infinite expansion). In most cases, such error will cause the entire search to fail immediately, but there are few exceptions to this rule, for which the search can backtrack and try an alternative path to fulfil the implicit argument. Either way, the Scala compiler error is only capable of showing the entry point of such loop or infinite expansion:\n\n```\ndiverging implicit expansion for type splain.DivergingImplicits.C\nstarting with method f in object Circular\n```\n\nIf the parameter `-P:splain:Vimplicits-diverging` is enabled, it will instruct the compiler to continue its implicit search process until an implicit resolution chain can be correlated with such error(s):\n\n```\nimplicit error;\n!I e: C\nf invalid because\n!I c: C\ndiverging implicit expansion for type C\nstarting with method f in object Endo\n――f invalid because\n  !I c: C\n  diverging implicit expansion for type C\n  starting with method f in object Endo\n```\n\n**EXPERIMENTAL!** sometimes this feature may cause failed implicit resolution to succeed, due to the delay in throwing the diverging implicit error. It may also increase compilation time slightly. If your build has been broken by this feature, please consider simplifying your code base to create a minimal reproducible test case, and submit it with a pull request.\n\n# type detail (experimental)\n\nThe option `-P:splain:Vtype-detail:X` can take an integer from 1 to 6 to attach different kinds of details to type information in any error message.\n\n- `1` (DEFAULT) : type info in short form, by using toString (same as pre-1.1.0)\n- `2` = **long** : type info in long form, by using toLongString\n- `3` = `2` + (**existential** : existential context)\n- `4` = `3` + (**reduction** : explain type reduction process)\n- `5` = `4` + (**position** : type definition position in code)\n- `6` = `5` + (**alias** : explain type aliases, this generally contains duplicate information with `3`, it is only included for completeness)\n\nFor example:\n\n(`-P:splain:Vtype-detail:1`)\n\n```\nXXX.scala:15: error: type mismatch;\n  Test.F[Test.a.type|a.type]\n```\n\n(`-P:splain:Vtype-detail:6`)\n\n![](img/bc959e77.png)\n\nIn addition, multiple names of the detail kind (denoted by bold text in the above list) can be appended to the option value to enable it, e.g. `-P:splain:Vtype-detail:1,reduction,position` can attach type reduction process & type definition position while bypassing **long** and **existential**.\n\n# type diffs detail (experimental)\n\nThe option `-P:splain:Vtype-diffs-detail:X` can take an integer from 1 to 4 to augment type diff errors with different kinds of details.\n\n- `1` (DEFAULT) : no augmentation (same as pre-1.1.0)\n- `2` = **disambiguation** : augment type info with disambiguation for both sides in `<found>|<required>` and infix types (e.g. `A =:= B`, `A <:< B`) in error message\n- `3` = `2` + (**builtIn** : attach built-in found/required errors emitted by Scala compiler IF AND ONLY IF both sides of the error message are identical)\n- `4` = `3` + (**builtInAlways** : ALWAYS attach original found/required error info, even if both sides of the error message are different)\n\nIn addition, multiple names of the detail kind (denoted by bold text in the above list) can be appended to the option value to enable it, e.g. `-P:splain:Vtype-diffs-detail:1,builtIn` can attach built-in errors while bypassing **disambiguation**.\n\nFor example:\n\n(`-P:splain:Vtype-diffs-detail:1`)\n\n```\nXXX.scala:16: error: implicit error;\n!I ev: Long =:= Long\n  Cannot prove that Long =:= Long.\n```\n\n(`-P:splain:Vtype-diffs-detail:4`)\n\n![](img/86df485f.png)\n\n# Development\n\n## Bugs\n\nDue to the nature of the hack that allows _splain_ to hook into the implicit search algorithm, other plugins using the\nsame trick may not work or cause _splain_ to be inactive.\n\nAnother victim of _splain_ is scaladoc – doc comments might disappear when running the task with _splain_ active, so\nmake sure it is disabled before doing so.\n\nUsers are encouraged to submit issues and test cases directly through pull requests, by forking the project and adding new test cases under:\n\n| v0.x                                   | v1.x                                               |\n|:-------------------------------------- | -------------------------------------------------- |\n| `<project root>/src/test/scala/splain` | `<project root>/core/src/test/scala/splain/plugin` |\n\nThe bug can thus be identified by the team quickly on our [continuous integration environment](https://github.com/tek/splain/actions). Submission on our GitHub issue tracker is also welcomed, but it generally takes much longer for the team to respond.\n\n## How to compile\n\n### v1.x (from git branch master)\n\nBuilt with the latest [Gradle](https://gradle.org/), to compile and publish locally:\n\n```\n./gradlew clean testClasses publishToMavenLocal\n```\n\nto run all tests:\n\n```\n./gradlew test\n```\n\n\n### v0.x (from git branch Maintenance/master)\n\nBuilt with the latest stable [SBT](https://www.scala-sbt.org/). to compile and publish locally:\n\n```\nsbt clean publishM2\n```\n\nto run all tests:\n\n```\nsbt test\n```\n\n\n## How to edit\n\nMost project contributors uses neovim, IntelliJ IDEA or visual studio code.\n\nThe team strive for a strong discipline in software engineering. All commits (including SNAPSHOTs and PRs) will be compliant with [scalalfmt](https://scalameta.org/scalafmt/) standard.\n\n## Communication\n\n- @tek - reviewer for built-in/v0.x bugfix, new features\n- @tribbloid - reviewer for v1.x bugfix\n- @dwijnand - reviewer for scala compiler integration\n"
  },
  {
    "path": "build.gradle.kts",
    "content": "import org.gradle.util.internal.VersionNumber\n\nimport com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask\nimport org.gradle.api.specs.Spec\n\nval vs = versions()\n\nbuildscript {\n    repositories {\n        // Add here whatever repositories you're already using\n        mavenCentral()\n    }\n\n    dependencies {\n        classpath(\"ch.epfl.scala:gradle-bloop_2.12:1.6.4\") // suffix is always 2.12, weird\n    }\n}\n\ntasks.named<DependencyUpdatesTask>(\"dependencyUpdates\").configure {\n    filterConfigurations = Spec<Configuration> {\n        !it.name.startsWith(\"incrementalScalaAnalysis\")\n    }\n}\n\nplugins {\n    `java-test-fixtures`\n\n    scala\n\n    idea\n\n    signing\n    `maven-publish`\n    id(\"io.github.gradle-nexus.publish-plugin\") version \"2.0.0\"\n\n    id(\"com.github.ben-manes.versions\") version \"0.53.0\"\n\n    id(\"io.github.cosmicsilence.scalafix\") version \"0.2.6\"\n}\n\nval sonatypeApiUser = providers.gradleProperty(\"sonatypeApiUser\")\nval sonatypeApiKey = providers.gradleProperty(\"sonatypeApiKey\")\nif (sonatypeApiUser.isPresent && sonatypeApiKey.isPresent) {\n    nexusPublishing {\n        repositories {\n            sonatype {\n\n                nexusUrl.set(uri(\"https://ossrh-staging-api.central.sonatype.com/service/local/\"))\n                snapshotRepositoryUrl.set(uri(\"https://central.sonatype.com/repository/maven-snapshots/\"))\n\n                username.set(sonatypeApiUser)\n                password.set(sonatypeApiKey)\n//                useStaging.set(true)\n            }\n        }\n    }\n} else {\n    logger.warn(\"Sonatype API key not defined, skipping configuration of Maven Central publishing repository\")\n}\n\nallprojects {\n\n    apply(plugin = \"java-library\")\n    apply(plugin = \"java-test-fixtures\")\n\n    // apply(plugin = \"bloop\")\n    // DO NOT enable! In VSCode it will cause the conflict:\n    // Cannot add extension with name 'bloop', as there is an extension already registered with that name\n\n    apply(plugin = \"scala\")\n    apply(plugin = \"idea\")\n\n    apply(plugin = \"signing\")\n    apply(plugin = \"maven-publish\")\n\n    group = vs.projectGroup\n    version = vs.projectV\n\n    repositories {\n        mavenCentral()\n//        jcenter()\n        maven(\"https://dl.bintray.com/kotlin/kotlin-dev\")\n        maven(\"https://scala-ci.typesafe.com/artifactory/scala-integration/\") // scala SNAPSHOT\n    }\n\n    fun includeShims(from: String, to: String) {\n        sourceSets {\n            main {\n                scala {\n                    setSrcDirs(srcDirs + listOf(\"src/main/scala-${from}+/${to}\"))\n                }\n                resources {\n                    setSrcDirs(srcDirs + listOf(\"src/main/resources-${from}+/${to}\"))\n                }\n            }\n            testFixtures {\n                scala {\n                    setSrcDirs(srcDirs + listOf(\"src/testFixtures/scala-${from}+/${to}\"))\n                }\n                resources {\n                    setSrcDirs(srcDirs + listOf(\"src/testFixtures/resources-${from}+/${to}\"))\n                }\n            }\n            test {\n                scala {\n                    setSrcDirs(srcDirs + listOf(\"src/test/scala-${from}+/${to}\"))\n                }\n                resources {\n                    setSrcDirs(srcDirs + listOf(\"src/test/resources-${from}+/${to}\"))\n                }\n            }\n        }\n    }\n\n    val vn = VersionNumber.parse(vs.scala.v)\n    val supportedPatchVs = 7..12\n\n    for (from in supportedPatchVs) {\n        if (vn.micro >= from) {\n\n            includeShims(\"2.13.${from}\", \"latest\")\n        }\n        for (to in supportedPatchVs) {\n            if (vn.micro <= to) {\n\n                includeShims(\"2.13.${from}\", \"2.13.${to}\")\n            }\n        }\n    }\n\n    dependencies {\n\n        constraints {}\n\n        implementation(\"${vs.scala.group}:scala-library:${vs.scala.v}\")\n\n        val scalaTestV = \"3.2.11\"\n        testFixturesApi(\"org.scalatest:scalatest_${vs.scala.artifactSuffix}:${scalaTestV}\")\n        testImplementation(\"org.scalatest:scalatest_${vs.scala.artifactSuffix}:${scalaTestV}\")\n//        testFixturesApi(\"org.scalatest:scalatest-core_${vs.scala.artifactSuffix}:${vs.scalaTestV}\")\n\n        val jUnitV = \"5.13.4\"\n        val jUnitPlatformV = \"1.13.4\"\n\n        testRuntimeOnly(\"org.junit.platform:junit-platform-engine:$jUnitPlatformV\")\n        testRuntimeOnly(\"org.junit.platform:junit-platform-launcher:$jUnitPlatformV\")\n        testImplementation(\"org.junit.jupiter:junit-jupiter:${jUnitV}\")\n//        testRuntimeOnly(\"org.scalatestplus:junit-5-13_${vs.scala.artifactSuffix}:3.2.19.0\")\n        testRuntimeOnly(\"ai.acyclic.scalatestplus:junit-5-13_${vs.scala.artifactSuffix}:3.2.19.2\")\n//        testRuntimeOnly(\"ai.acyclic.scalatestplus:junit-5-13_${vs.scala.artifactSuffix}:3.3.0.0\")\n    }\n\n    tasks.register(\"dependencyTree\") {\n\n        dependsOn(\"dependencies\")\n    }\n\n    val jvmTarget = JavaVersion.VERSION_1_8\n\n    java {\n\n        withSourcesJar()\n        withJavadocJar()\n\n        sourceCompatibility = jvmTarget\n        targetCompatibility = jvmTarget\n    }\n\n    tasks {\n\n        withType<ScalaCompile> {\n\n            sourceCompatibility = jvmTarget.toString()\n            targetCompatibility = jvmTarget.toString()\n\n            scalaCompileOptions.apply {\n\n//                    isForce = true\n\n                loggingLevel = \"verbose\"\n\n                val compilerOptions =\n\n                    mutableListOf(\n                        \"-encoding\", \"UTF-8\",\n\n                        \"-deprecation\",\n                        \"-unchecked\",\n                        \"-feature\",\n                        \"-language:higherKinds\",\n                        \"-language:existentials\",\n                        \"-Ywarn-value-discard\",\n                        \"-Ywarn-unused:imports\",\n                        \"-Ywarn-unused:implicits\",\n                        \"-Ywarn-unused:params\",\n                        \"-Ywarn-unused:patvars\"\n//                        \"-Ydebug-error\"\n                    )\n\n                additionalParameters = compilerOptions\n\n                forkOptions.apply {\n\n                    memoryInitialSize = \"1g\"\n                    memoryMaximumSize = \"4g\"\n\n                    // this may be over the top but the test code in macro & core frequently run implicit search on church encoded Nat type\n                    jvmArgs = listOf(\n                        \"-Xss256m\"\n                    )\n                }\n            }\n        }\n\n        test {\n\n            minHeapSize = \"1024m\"\n            maxHeapSize = \"4096m\"\n\n            testLogging {\n                showExceptions = true\n                showCauses = true\n                showStackTraces = true\n\n                // stdout is used for occasional manual verification\n                showStandardStreams = true\n            }\n\n//            useJUnit()\n            useJUnitPlatform {\n                includeEngines(\"scalatest\")\n                testLogging {\n                    events(\"passed\", \"skipped\", \"failed\")\n                }\n            }\n        }\n    }\n\n    apply(plugin = \"io.github.cosmicsilence.scalafix\")\n    scalafix {\n        semanticdb.autoConfigure.set(true)\n        semanticdb.version.set(\"4.9.0\")\n    }\n\n    idea {\n\n        module {\n\n            excludeDirs = excludeDirs + files(\n\n                \"target\",\n                \"out\",\n\n                \".idea\",\n                \".vscode\",\n                \".bloop\",\n                \".bsp\",\n                \".metals\",\n                \"bin\",\n\n                \".ammonite\",\n\n                \"logs\",\n\n                )\n\n            isDownloadJavadoc = true\n            isDownloadSources = true\n        }\n    }\n}\n\nsubprojects {\n\n    // https://stackoverflow.com/a/66352905/1772342\n\n//    val signingKeyID = providers.gradleProperty(\"signing.gnupg.keyID\")\n    val signingSecretKey = providers.gradleProperty(\"signing.gnupg.secretKey\")\n    val signingKeyPassphrase = providers.gradleProperty(\"signing.gnupg.passphrase\")\n    signing {\n        useGpgCmd()\n        if (signingSecretKey.isPresent) {\n            useInMemoryPgpKeys(signingSecretKey.get(), signingKeyPassphrase.get())\n//            useInMemoryPgpKeys(signingKeyID.get(), signingSecretKey.get(), signingKeyPassphrase.get())\n            sign(extensions.getByType<PublishingExtension>().publications)\n        } else {\n            logger.warn(\"PGP signing key not defined, skipping signing configuration\")\n        }\n    }\n\n    publishing {\n        val suffix = \"_\" + vs.scala.v\n\n        val rootID = vs.projectRootID\n\n        val moduleID =\n            if (project.name.equals(rootID))// rootID + \"-\" + \"parent\" + suffix\n                throw kotlin.UnsupportedOperationException(\"root project should not be published\")\n            else if (project.name.equals(\"core\")) rootID + suffix\n            else rootID + \"-\" + project.name + suffix\n\n        val whitelist = setOf(\"core\")\n\n        if (whitelist.contains(project.name)) {\n\n            publications {\n                create<MavenPublication>(\"maven\") {\n\n                    val javaComponent = components[\"java\"] as AdhocComponentWithVariants\n                    from(javaComponent)\n\n                    javaComponent.withVariantsFromConfiguration(configurations[\"testFixturesApiElements\"]) { skip() }\n                    javaComponent.withVariantsFromConfiguration(configurations[\"testFixturesRuntimeElements\"]) { skip() }\n\n                    artifactId = moduleID\n                    version = project.version.toString()\n\n                    pom {\n                        licenses {\n                            license {\n                                name.set(\"MIT\")\n                                url.set(\"http://opensource.org/licenses/MIT\")\n                            }\n                        }\n\n                        name.set(\"splain\")\n                        description.set(\"A scala compiler plugin for more concise errors\")\n\n                        val github = \"https://github.com/tek\"\n                        val repo = github + \"/splain\"\n\n                        url.set(repo)\n\n                        developers {\n                            developer {\n                                id.set(\"tryp\")\n                                name.set(\"Torsten Schmits\")\n                                email.set(\"torstenschmits@gmail.com\")\n                                url.set(github)\n                            }\n                        }\n                        scm {\n                            connection.set(\"scm:git@github.com:tek/splain\")\n                            url.set(repo)\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n\nidea {\n\n    targetVersion = \"2020\"\n\n    module {\n\n        excludeDirs = excludeDirs + files(\n            \".gradle\",\n            \"gradle\",\n            \"spike\",\n            \".history\"\n        )\n    }\n}"
  },
  {
    "path": "buildSrc/build.gradle.kts",
    "content": "plugins {\n    `kotlin-dsl`\n}\n\nrepositories {\n    mavenLocal()\n    mavenCentral()\n//    jcenter()\n    maven(\"https://dl.bintray.com/kotlin/kotlin-dev\")\n}\n"
  },
  {
    "path": "buildSrc/src/main/kotlin/Versions.kt",
    "content": "import org.gradle.api.Project\n\nclass Versions(private val project: Project) {\n\n    // TODO : how to group them?\n    val projectGroup = \"io.tryp\"\n    val projectRootID = \"splain\"\n\n    val projectVMajor = \"1.2.0\"\n    val projectV = projectVMajor + \"-SNAPSHOT\"\n\n    inner class Scala {\n        val group: String = project.properties[\"scalaGroup\"]?.toString() ?: \"org.scala-lang\"\n\n        val v: String = project.properties[\"scalaVersion\"].toString()\n        protected val vParts: List<String> = v.split('.').also { parts ->\n            require(parts.size == 3) { \"Scala version must be in format 'X.Y.Z' but was: $v\" }\n        }\n\n        val majorV: String = vParts[0]\n        val binaryV: String = vParts.subList(0, 2).joinToString(\".\")\n        val patchV: String = vParts[2]\n\n        val artifactSuffix = run {\n            if (majorV == \"3\") majorV\n            else binaryV\n        }\n\n        val jsV: String? = project.properties.get(\"scalaJSVersion\")?.toString()\n    }\n\n    val scala: Scala by lazy { Scala() }\n}\n"
  },
  {
    "path": "buildSrc/src/main/kotlin/init.kt",
    "content": "import org.gradle.api.Project\n\n/**\n * Configures the current project as a Kotlin project by adding the Kotlin `stdlib` as a dependency.\n */\nfun Project.versions(): Versions {\n\n    return Versions(this)\n}\n"
  },
  {
    "path": "core/build.gradle.kts",
    "content": "val vs: Versions = versions()\n\ndependencies {\n\n    // see https://github.com/gradle/gradle/issues/13067\n    fun bothImpl(constraintNotation: Any) {\n        implementation(constraintNotation)\n        testFixturesImplementation(constraintNotation)\n    }\n\n    bothImpl(\"${vs.scala.group}:scala-compiler:${vs.scala.v}\")\n\n    testFixturesApi(\"com.chuusai:shapeless_${vs.scala.binaryV}:2.3.7\")\n\n    testFixturesApi(\"dev.zio:zio_${vs.scala.binaryV}:1.0.18\")\n\n    testFixturesApi(\"org.slf4j:slf4j-api:2.0.9\")\n    testRuntimeOnly(\"org.slf4j:slf4j-simple:2.0.9\")\n}"
  },
  {
    "path": "core/src/main/resources/scalac-plugin.xml",
    "content": "<plugin>\n    <name>splain</name>\n    <classname>splain.SplainPlugin</classname>\n</plugin>\n"
  },
  {
    "path": "core/src/main/scala/splain/Messages.scala",
    "content": "package splain\n\nobject Messages {\n  val hasMatching = \"hasMatchingSymbol reported error: \"\n\n  val typingTypeApply = \"typing TypeApply reported errors for the implicit tree: \"\n\n  val lazyDeriv = \"could not find Lazy implicit\"\n\n  val WARNING = \"[WARNING] \"\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/PluginSettings.scala",
    "content": "package splain\n\nimport splain.PluginSettings.Keys.Key\n\nimport scala.collection.mutable\nimport scala.reflect.NameTransformer\nimport scala.util.{Failure, Success}\n\ncase class PluginSettings(pluginOpts: mutable.Map[String, String]) {}\n\nobject PluginSettings {\n\n  case class IntKey(initV: Int) extends Keys.Key[Int] {\n    override def parse(s: String): Int = s.toInt\n  }\n\n  case class BooleanKey(initV: Boolean) extends Key[Boolean] {\n    override def parse(s: String): Boolean = s.toBoolean\n  }\n\n  case class StringKey(initV: String) extends Key[String] {\n    override def parse(s: String): String = s\n  }\n\n  object Keys extends Enumeration {\n\n    trait Key[T] extends Val with Product {\n\n      def initV: T\n\n      def parse(s: String): T\n\n      def name: String = NameTransformer.decode(toString)\n    }\n\n    val enabled: BooleanKey = BooleanKey(true)\n\n    val debug: BooleanKey = BooleanKey(false)\n\n    val `Vimplicits-diverging`: BooleanKey = BooleanKey(false)\n\n    val `Vimplicits-diverging-max-depth`: IntKey = IntKey(100)\n\n    val `Vtype-detail`: StringKey = StringKey(\"1\")\n\n    val `Vtype-diffs-detail`: StringKey = StringKey(\"1\")\n  }\n\n  lazy val nameToKey: List[(String, Key[_])] = {\n    val vs = Keys.values.toList\n      .collect { case v: Keys.Key[_] => v }\n\n    vs.map { v =>\n      v.name -> v\n    }\n\n  }\n\n  lazy val nameToInitValue: List[(String, String)] = nameToKey.map { case (k, v) => k -> v.initV.toString }\n\n  object TypeDetail extends Enumeration {\n\n    val long: Value = Value(2)\n    val existential: Value = Value(3)\n    val reduction: Value = Value(4)\n    val position: Value = Value(5)\n    val alias: Value = Value(6)\n  }\n\n  object TypeDiffsDetail extends Enumeration {\n\n    val disambiguation: Value = Value(2)\n    val `builtin-msg`: Value = Value(3)\n    val `builtin-msg-always`: Value = Value(4)\n  }\n\n  trait Implicits {\n\n    def pluginSettings: PluginSettings\n\n    implicit class KeyOps[T](self: Key[T]) {\n\n      def get: T = {\n\n        val key = self.name\n        pluginSettings.pluginOpts\n          .get(key)\n          .map(self.parse)\n          .getOrElse(\n            throw new UnsupportedOperationException(s\"$key is not defined\")\n          )\n      }\n    }\n\n    implicit class BooleanKeyOps(self: BooleanKey) {\n\n      def isEnabled: Boolean = {\n        Keys.enabled.get && self.get\n      }\n    }\n\n    case class DetailParsing[T <: Enumeration](key: StringKey, valueEnum: T) {\n\n      lazy val raw: Seq[String] = key.get\n        .split(',')\n        .toList\n        .map(_.trim)\n        .filter { s =>\n          s.nonEmpty\n        }\n\n      lazy val (number: Int, refined: Seq[valueEnum.Value]) = {\n\n        val classified = raw.map { s =>\n          scala.util.Try(s.toInt) match {\n            case Failure(_) => Left(s)\n            case Success(v) => Right(v)\n          }\n        }\n\n        val refined: Seq[valueEnum.Value] = classified collect {\n          case Left(v) =>\n            valueEnum.withName(v)\n        }\n        val numbers: Seq[Int] = classified collect { case Right(v) => v }\n\n        require(numbers.size <= 1, \"only one numeric value is allowed\")\n\n        numbers.headOption.getOrElse(1) -> refined\n      }\n\n      trait ValueOps {\n\n        val self: valueEnum.Value\n\n        def isEnabled: Boolean = {\n\n          Keys.enabled.get &&\n          (number >= self.id || refined.contains(self))\n        }\n      }\n    }\n\n    val typeDetailParsing: DetailParsing[TypeDetail.type] =\n      DetailParsing(Keys.`Vtype-detail`, TypeDetail)\n    implicit class TypeDetailValueOps(val self: TypeDetail.Value) extends typeDetailParsing.ValueOps {}\n\n    val typeDiffsDetailParsing: DetailParsing[TypeDiffsDetail.type] =\n      DetailParsing(Keys.`Vtype-diffs-detail`, TypeDiffsDetail)\n    implicit class TypeDiffsDetailValueOps(val self: TypeDiffsDetail.Value) extends typeDiffsDetailParsing.ValueOps {}\n\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/SplainInternalError.scala",
    "content": "package splain\n\nclass SplainInternalError(detail: String, cause: Throwable = null)\n    extends InternalError(\n      \"You've found a bug in splain formatting extension,\" +\n        \" please post this error with stack trace on https://github.com/tek/splain/issues\\n\\n\" +\n        detail,\n      cause\n    ) {}\n"
  },
  {
    "path": "core/src/main/scala/splain/format/package.scala",
    "content": "package splain\n\npackage object format {\n\n  // TODO: this entire package could be gone, already taken over by scalac formatting\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/test/AutoLift.scala",
    "content": "package splain.test\n\nimport java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}\nimport java.util.Base64\nimport scala.reflect.macros.blackbox\n\ntrait AutoLift {\n\n  type Bound\n\n  def asCode(value: Bound): String\n\n  trait Mixin {\n\n    val c: blackbox.Context\n    import c.universe._\n\n    implicit def _liftable[T <: Bound]: Liftable[T] = Liftable.apply { value: T =>\n      val code = asCode(value)\n\n      val parsed = c.parse(code)\n      parsed\n    }\n  }\n}\n\nobject AutoLift {\n\n  val MAX_LITERAL_LENGTH = 32768\n\n  object SerializingLift extends AutoLift {\n\n    type Bound = Serializable\n\n    lazy val encoder: Base64.Encoder = Base64.getEncoder\n    lazy val decoder: Base64.Decoder = Base64.getDecoder\n\n    lazy val fullPath: String = this.getClass.getCanonicalName.stripSuffix(\"$\")\n\n    override def asCode(value: Bound): String = {\n\n      val bOStream = new ByteArrayOutputStream()\n      val oOStream = new ObjectOutputStream(bOStream)\n\n      oOStream.writeObject(value)\n\n      val serialized = encoder.encodeToString(bOStream.toByteArray)\n\n      val chunks = serialized.sliding(MAX_LITERAL_LENGTH, MAX_LITERAL_LENGTH).toList\n\n      val chunkExpr = chunks\n        .map { cc =>\n          s\"\\\"$cc\\\"\"\n        }\n        .mkString(\"(\", \", \", \")\")\n\n      val typeStr = {\n        val canonicalName = value.getClass.getCanonicalName\n        if (canonicalName.endsWith(\"$\"))\n          canonicalName.stripSuffix(\"$\") + \".type\"\n        else canonicalName\n      }\n\n      val result = s\"\"\"\n         |$fullPath.fromPreviousStage[$typeStr]$chunkExpr\n         |\"\"\".stripMargin\n\n      result\n    }\n\n    def fromPreviousStage[T <: Serializable](strs: String*): T = {\n\n      val bytes = strs\n        .map { str =>\n          decoder.decode(str)\n        }\n        .reduce(_ ++ _)\n\n      val bIStream = new ByteArrayInputStream(bytes)\n      val oIStream = new ObjectInputStream(bIStream)\n\n      val v = oIStream.readObject()\n      v.asInstanceOf[T]\n    }\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/test/CachingFrontEnd.scala",
    "content": "package splain.test\n\nimport scala.collection.mutable.ArrayBuffer\nimport scala.tools.reflect.FrontEnd\n\n// mimic of StoreReporter\ncase class CachingFrontEnd(sourceName: String) extends FrontEnd {\n\n  val cached: ArrayBuffer[Issue] = ArrayBuffer.empty[Issue]\n\n  override def display(info: Info): Unit = {\n\n    val issue = Issue(\n      info.severity.id,\n      info.msg,\n      info.pos,\n      sourceName\n    )\n\n    this.cached += issue\n  }\n\n  override def reset(): Unit = {\n    super.reset()\n    cached.clear()\n  }\n}\n\nobject CachingFrontEnd {\n\n  object NoSource extends CachingFrontEnd(\"\")\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/test/Issue.scala",
    "content": "package splain.test\n\nimport scala.collection.immutable.ArraySeq\nimport scala.reflect.internal.util.{BatchSourceFile, NoPosition, Position}\nimport scala.util.Try\n\n@SerialVersionUID(5124466488126506935L)\ncase class Issue(\n    severity: Int,\n    msg: String,\n    @transient pos: Position,\n    sourceName: String = Issue.defaultSrcName,\n    isShortName: Boolean = false\n) extends Serializable {\n\n  // mimic of PrintReporter.display\n  val display: String = {\n\n    lazy val severityDisplay: String = new CachingFrontEnd.NoSource.Severity(severity).toString.toLowerCase\n\n    val posWithFileName = Try(\n      pos.withSource(\n        new BatchSourceFile(sourceName, ArraySeq.unsafeWrapArray(pos.source.content))\n      )\n    )\n\n    val infoStr = s\"$severityDisplay: $msg\"\n\n    val result = posWithFileName\n      .map { pos =>\n        val formatted = Position.formatMessage(pos, infoStr, shortenFile = true)\n        formatted\n      }\n      .recover {\n        case ee: Exception =>\n          val formatted = Position.formatMessage(\n            NoPosition,\n            s\"\"\"$infoStr\n               |with error: $ee\n               |\"\"\".stripMargin,\n            shortenFile = true\n          )\n          formatted\n\n      }\n      .get\n\n    result\n  }\n\n  override def toString: String = {\n\n    display\n  }\n}\n\nobject Issue {\n\n  lazy val defaultSrcName: \"newSource1.scala\" = \"newSource1.scala\"\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/test/TryCompile.scala",
    "content": "package splain.test\n\nimport scala.language.experimental.macros\nimport scala.language.implicitConversions\nimport scala.reflect.runtime.{currentMirror, universe}\nimport scala.tools.nsc.reporters.{Reporter, StoreReporter}\nimport scala.tools.nsc.{Global, Settings}\nimport scala.tools.reflect.ToolBox\n\ntrait TryCompile extends Product with Serializable {\n\n  def issues: Seq[Issue]\n\n  case class Level(level: Int) {\n\n    def filteredIssues: Seq[Issue] = issues.filter { i =>\n      i.severity == level\n    }\n\n    def displayIssues: String = issues\n      .map { i =>\n        i.display\n      }\n      .mkString(\"\\n\")\n  }\n\n  object Error extends Level(2)\n  object Warning extends Level(1)\n  object Info extends Level(0)\n\n  override lazy val toString: String = {\n    s\"\"\"\n       |$productPrefix\n       | ---\n       |${issues.mkString(\"\\n\\n\")}\n       |\"\"\".stripMargin\n  }\n}\n\nobject TryCompile {\n\n  trait Resolved extends TryCompile\n\n  case class Success(\n      issues: Seq[Issue] = Nil\n  ) extends Resolved {\n\n    abstract class Evaluable extends Success(issues) {\n\n      def get: Any\n    }\n  }\n\n  object Empty extends Success()\n\n  trait Failure extends Resolved\n\n  case class TypingError(issues: Seq[Issue] = Nil) extends Failure\n  case class ParsingError(issues: Seq[Issue] = Nil) extends Failure\n  case class OtherFailure(e: Throwable) extends Failure {\n    override def issues: Seq[Issue] = Nil\n  }\n\n  trait Engine {\n\n    def args: String\n\n    final def apply(code: String): TryCompile =\n      try {\n        doCompile(code)\n      } catch {\n        case e: Throwable =>\n          OtherFailure(e)\n      }\n\n    def doCompile(code: String): TryCompile\n  }\n\n  val mirror: universe.Mirror = currentMirror\n\n  case class UseReflect(args: String, sourceName: String = Issue.defaultSrcName) extends Engine {\n\n    override def doCompile(code: String): TryCompile = {\n\n      val frontEnd = CachingFrontEnd(sourceName)\n\n      val toolBox: ToolBox[universe.type] = mirror.mkToolBox(frontEnd, options = args)\n\n      def cached: Seq[Issue] = frontEnd.cached.toSeq\n\n      val parsed =\n        try {\n          toolBox.parse(code.trim)\n        } catch {\n          case _: Throwable =>\n            return TryCompile.ParsingError(cached)\n        }\n\n      val compiled =\n        try {\n//        toolBox.typecheck(parsed, withImplicitViewsDisabled = false)\n          toolBox.compile(parsed)\n        } catch {\n          case _: Throwable =>\n            return TryCompile.TypingError(cached)\n        }\n\n      val success = Success(cached)\n      new success.Evaluable {\n        override def get: Any = compiled()\n      }\n\n    }\n  }\n\n  case class UseNSC(args: String, sourceName: String = Issue.defaultSrcName) extends Engine {\n\n    val global: Global = {\n      val _settings = new Settings()\n\n      _settings.reporter.value = classOf[StoreReporter].getCanonicalName\n      _settings.usejavacp.value = true\n      _settings.processArgumentString(args)\n\n      val global: Global = Global(_settings, Reporter(_settings))\n      global\n    }\n\n    val reporter: StoreReporter = global.reporter.asInstanceOf[StoreReporter]\n\n    override def doCompile(code: String): TryCompile = reporter.synchronized { // shared reporter is not thread safe\n\n      reporter.reset()\n\n      val tree = global.newCompilationUnit(code.trim, sourceName)\n\n      val run = new global.Run()\n\n      val parser = global.newUnitParser(tree)\n      parser.parse()\n\n      def reports = reporter.infos.toSeq.map { info =>\n        Issue(info.severity.id, info.msg, info.pos, sourceName)\n      }\n\n      val result = if (reports.exists(v => v.severity == Empty.Error.level)) {\n\n        ParsingError(reports)\n      } else {\n\n        run.compileUnits(List(tree))\n\n        val success = Success(reports)\n        if (success.Error.filteredIssues.nonEmpty) {\n          TypingError(reports)\n        } else {\n          success\n        }\n      }\n\n      result\n    }\n  }\n\n  case class Static[N <: String with Singleton](sourceName: N) {\n\n    type NN = N\n\n    def apply(code: String): TryCompile = macro TryCompileMacros.compileCodeTree[N]\n\n    trait FromCodeMixin {\n\n      implicit def code2TryCompile(code: String): TryCompile = macro TryCompileMacros.compileCodeTree[N]\n    }\n  }\n\n  object Static {\n\n    val default: Static[\"newSource1.scala\"] = Static(Issue.defaultSrcName)\n\n    def apply(): Static[\"newSource1.scala\"] = default\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala/splain/test/TryCompileMacros.scala",
    "content": "package splain.test\n\nimport splain.test.AutoLift.SerializingLift\n\nimport scala.collection.mutable.ArrayBuffer\nimport scala.reflect.macros.{whitebox, ParseException, TypecheckException}\nimport scala.tools.nsc.Global\nimport scala.tools.nsc.reporters.FilteringReporter\n\nclass TryCompileMacros(val c: whitebox.Context) extends SerializingLift.Mixin {\n  import c.universe._\n\n  lazy val global: Global = c.universe.asInstanceOf[Global]\n\n  def reporter: FilteringReporter = global.reporter\n\n  lazy val defaultSrcLit: Literal = Literal(Constant(Issue.defaultSrcName))\n\n  type CodeTree = Tree\n\n  // TODO: from shapeless.test.IllTypedMacros, no idea what it is for\n  def rectifyCode(codeStr: String): String = {\n\n    val dummy0 = TermName(c.freshName())\n    val dummy1 = TermName(c.freshName())\n    s\"object $dummy0 { val $dummy1 = { $codeStr } }\"\n  }\n\n  final def tree2Str(code: CodeTree): String = {\n\n    code match {\n      case Literal(v) =>\n        v.value.asInstanceOf[String]\n      case _ =>\n        throw new UnsupportedOperationException(\n          s\"`$code` (${code.getClass.getName}) is not a Literal, please only use Literal or final val with refined or no type annotation\"\n        )\n    }\n  }\n\n  final def type2Str(tt: Type): String = {\n\n    tt.dealias match {\n      case v: ConstantType => v.value.value.asInstanceOf[String]\n      case _ =>\n        throw new UnsupportedOperationException(\n          s\"cannot parse type $tt : ${tt.getClass}\"\n        )\n    }\n  }\n\n  def compileCodeTree[N <: String with Singleton: c.WeakTypeTag](code: CodeTree): Tree = {\n\n    val _code = tree2Str(code).trim\n\n    val _name = type2Str(implicitly[c.WeakTypeTag[N]].tpe)\n\n    val result = run(_code, _name)\n\n    result\n  }\n\n  def run(codeStr: String, sourceName: String): Tree = {\n\n    val cached = ArrayBuffer.empty[Issue]\n\n    val parsed =\n      try {\n        c.parse(codeStr)\n      } catch {\n        case e: ParseException =>\n          cached += Issue(\n            TryCompile.Empty.Error.level,\n            e.msg,\n            e.pos.asInstanceOf[scala.reflect.internal.util.Position],\n            sourceName\n          )\n\n          val result = TryCompile.ParsingError(cached.toSeq)\n\n          return q\"$result\"\n      }\n\n    val compiled: c.Tree =\n      try {\n        c.typecheck(parsed)\n      } catch {\n        case e: TypecheckException =>\n          cached += Issue(\n            TryCompile.Empty.Error.level,\n            e.msg,\n            e.pos.asInstanceOf[scala.reflect.internal.util.Position],\n            sourceName\n          )\n          // TODO: this can only capture the first error, which makes the result different from runtime compilation\n          //   unfortunately there is nothing we can do\n\n          val result = TryCompile.TypingError(cached.toSeq)\n\n          return q\"$result\"\n      }\n\n    val success = TryCompile.Success(cached.toSeq)\n\n//    q\"$success\"\n\n    q\"\"\"\n      val ss = $success\n\n      new ss.Evaluable {\n        override def get: Any = {\n          $compiled\n        }\n      }\n     \"\"\"\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/ImplicitsExtension.scala",
    "content": "package splain\n\nimport scala.collection.concurrent.TrieMap\nimport scala.collection.mutable\nimport scala.tools.nsc.typechecker\n\ntrait ImplicitsExtension extends TyperCompatViews with typechecker.Implicits {\n  self: SplainAnalyzer =>\n\n  import global._\n\n  object ImplicitsHistory {\n\n    lazy val currentGlobal: Global = {\n      val result = Global()\n      result\n    }\n\n    case class Global() {\n\n      val localByPosition: TrieMap[PositionIndex, Local] = TrieMap.empty\n    }\n\n    case class Local() {\n\n      object DivergingImplicitErrors {\n\n        val errors: mutable.ArrayBuffer[DivergentImplicitTypeError] = mutable.ArrayBuffer.empty\n\n        def push(v: DivergentImplicitTypeError): Unit = {\n          errors.addOne(v)\n        }\n\n        val linkedErrors = mutable.HashSet.empty[DivergentImplicitTypeError]\n\n        def getUnlinkedMsgs: Seq[String] = {\n\n          val Seq(msgs, linkedMsgs) = Seq(errors.toSeq, linkedErrors.toSeq).map { seq =>\n            seq.map(v => DivergingImplicitErrorView(v).errMsg).distinct\n          }\n\n          val linkedMsgSet = linkedMsgs.toSet\n\n          val result = msgs.filterNot { str =>\n            linkedMsgSet.contains(str)\n          }\n\n          result\n        }\n\n        val logs: mutable.ArrayBuffer[String] = mutable.ArrayBuffer.empty[String]\n        // unused messages & comments will be displayed at the end of the implicit error\n      }\n    }\n  }\n\n  override def inferImplicit(\n      tree: Tree,\n      pt: Type,\n      reportAmbiguous: Boolean,\n      isView: Boolean,\n      context: Context,\n      saveAmbiguousDivergent: Boolean,\n      pos: Position\n  ): SearchResult = {\n\n    import ImplicitsHistory._\n    import PluginSettings.Keys._\n\n    def getResult = super.inferImplicit(tree, pt, reportAmbiguous, isView, context, saveAmbiguousDivergent, pos)\n\n    if (settings.Vimplicits.value && `Vimplicits-diverging`.isEnabled) {\n\n      val posII = PositionIndex(\n        tree.pos\n      )\n\n      val local = currentGlobal.localByPosition.getOrElseUpdate(posII, Local())\n      val previousSimilarErrors = local.DivergingImplicitErrors.errors.filter { ee =>\n        ee.underlyingTree equalsStructure tree\n      }\n\n      val previousSimilarErrorsN = previousSimilarErrors.size\n      if (previousSimilarErrorsN >= `Vimplicits-diverging-max-depth`.get) {\n\n        local.DivergingImplicitErrors.logs +=\n          s\"\"\"\n             |Implicit search for $tree\n             |has reported $previousSimilarErrorsN diverging errors\n             |Terminated\n             |    at ${pos.showDebug}\n             |\"\"\".stripMargin.trim\n\n//        s\"Terminating implicit search for $tree at ${pos.showDebug} \" +\n//          s\"after reporting ${settingVImplicitDivergingThreshold} Diverging implicit errors\"\n        return SearchFailure\n      }\n\n      val result = getResult\n\n      val divergingErrors = context.reporter.errors.collect {\n        case ee: DivergentImplicitTypeError =>\n          ee\n      }\n\n      divergingErrors.foreach { ee =>\n        local.DivergingImplicitErrors.push(ee)\n\n//        require(ee.pt0 == pt, s\"mismatch! ${ee.pt0} != $pt\")\n\n        context.reporter.retainDivergentErrorsExcept(ee)\n      }\n\n//      val cc = result.isSuccess || result == SearchFailure\n\n      result\n    } else {\n\n      val result: SearchResult = getResult\n      result\n    }\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainAnalyzer.scala",
    "content": "package splain\n\nimport scala.collection.mutable\nimport scala.tools.nsc._\n\nclass SplainAnalyzer(val global: Global, val pluginSettings: PluginSettings)\n    extends typechecker.Analyzer\n    with SplainFormattingExtension\n    with ImplicitsExtension\n    with SplainAnalyzerShim\n    with PluginSettings.Implicits {\n\n  override val specialFormatters: List[SpecialFormatter] =\n    List(\n      FunctionFormatter,\n      TupleFormatter,\n      ShapelessRecordItemFormatter,\n      RefinedFormatterImproved,\n//      RefinedFormatter,\n      ByNameFormatter\n    )\n\n  override def splainFoundReqMsg(found: global.Type, req: global.Type): String = {\n    val original = super.splainFoundReqMsg(found, req)\n\n    val extra = mutable.Buffer.empty[String]\n\n    if (PluginSettings.Keys.debug.isEnabled) {\n\n      extra += \"===[ ORIGINAL ERROR ]===\" +\n        builtinFoundReqMsg(found, req) +\n        \"\\n\"\n    }\n\n    val result = (Seq(original) ++ extra.toSeq).mkString(\"\\n\")\n    result\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainAnalyzerShim.scala",
    "content": "package splain\n\nimport scala.tools.nsc.typechecker.Analyzer\n\ntrait SplainAnalyzerShim {\n  self: SplainAnalyzer =>\n\n  def migrateFrom(old: Analyzer): Unit = {\n\n    // fix for #81: transfer deferredOpen that are cached before this initializer\n    old.packageObjects.deferredOpen.foreach { v =>\n      self.packageObjects.deferredOpen.add(v.asInstanceOf[self.global.Symbol])\n    }\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainFormattersExtension.scala",
    "content": "package splain\n\nimport scala.tools.nsc.typechecker.splain._\n\nobject SplainFormattersExtension {}\n\ntrait SplainFormattersExtension extends SplainFormatters {\n  self: SplainAnalyzer =>\n\n  import global._\n\n  object RefinedFormatterImproved extends SpecialFormatter {\n\n    object DeclSymbol {\n      def unapply(sym: Symbol): Option[(Formatted, Formatted)] =\n        if (sym.hasRawInfo)\n          Some((Simple(sym.simpleName.toString), formatType(sym.rawInfo, top = true)))\n        else\n          None\n    }\n\n    val ignoredTypes: List[Type] = List(typeOf[Object], typeOf[Any], typeOf[AnyRef])\n\n    def sanitizeParents: List[Type] => List[Type] = { ps =>\n      val tpes = ps.distinct\n      val result = tpes.filterNot(t => ignoredTypes.exists(_ =:= t))\n\n      if (result.isEmpty) tpes.headOption.toList\n      else result\n    }\n\n    object Refined {\n      def unapply(tpe: Type): Option[(List[Type], Scope)] =\n        tpe match {\n          case TypeRef(pre, sym, List(RefinedType(parents, decls)))\n              if decls.isEmpty && pre.typeSymbol.fullName == \"zio\" && sym.fullName == \"zio.Has\" =>\n            val sanitized = sanitizeParents(parents)\n            if (sanitized.length == 1)\n              Some((List(TypeRef(pre, sym, sanitized.headOption.toList)), decls))\n            else\n              None\n          case RefinedType(types, scope) =>\n            if (scope.isEmpty) {\n              val subtypes = types.map(v => dealias(v)).flatMap {\n                case Refined(types, _) =>\n                  types\n                case tpe =>\n                  List(tpe)\n              }\n              Some((subtypes, scope))\n            } else\n              Some((types, scope))\n          case t @ SingleType(_, _) =>\n            unapply(t.underlying)\n          case _ =>\n            None\n        }\n    }\n\n    def formatDecl: Symbol => Formatted = {\n      case sym if sym.hasRawInfo && sym.rawInfo.isInstanceOf[TypeBounds] =>\n        val name = sym.simpleName.toString\n        val bounds = formatType(sym.rawInfo, top = true)\n        val boundsStr = self.showFormatted(bounds)\n        Simple(s\"type $name$boundsStr\")\n      case DeclSymbol(n, t) =>\n        Decl(n, t)\n      case sym =>\n        Simple(sym.toString)\n    }\n\n    val none: Formatted = Simple(\"<none>\")\n\n    def separate[A](left: List[A], right: List[A]): (List[A], List[A], List[A]) = {\n      val leftS = Set(left: _*)\n      val rightS = Set(right: _*)\n      val common = leftS.intersect(rightS)\n      val uniqueLeft = leftS -- common\n      val uniqueRight = rightS -- common\n      (common.toList, uniqueLeft.toList, uniqueRight.toList)\n    }\n\n    def compareTypes(left: List[Type], right: List[Type]): List[Formatted] = {\n      val (common, uniqueLeft, uniqueRight) =\n        separate(left.map(formatType(_, top = true)), right.map(formatType(_, top = true)))\n      val diffs = uniqueLeft\n        .zipAll(uniqueRight, none, none)\n        .map {\n          case (l, r) =>\n            Diff(l, r)\n        }\n      common ++ diffs\n    }\n\n    def filterDecls(syms: List[Symbol]): List[(Formatted, Formatted)] =\n      syms.collect {\n        case DeclSymbol(sym, rhs) =>\n          (sym, rhs)\n      }\n\n    def compareDecls(left: List[Symbol], right: List[Symbol]): List[Formatted] = {\n      val (common, uniqueLeft, uniqueRight) = separate(filterDecls(left), filterDecls(right))\n      val diffs = uniqueLeft\n        .map(Some(_))\n        .zipAll(uniqueRight.map(Some(_)), None, None)\n        .collect {\n          case (Some((sym, l)), Some((_, r))) =>\n            DeclDiff(sym, l, r)\n          case (None, Some((sym, r))) =>\n            DeclDiff(sym, none, r)\n          case (Some((sym, l)), None) =>\n            DeclDiff(sym, l, none)\n        }\n      common.map {\n        case (sym, rhs) =>\n          Decl(sym, rhs)\n      } ++ diffs\n    }\n\n    override def apply[A](\n        tpe: Type,\n        simple: String,\n        args: List[A],\n        formattedArgs: => List[Formatted],\n        top: Boolean\n    )(rec: (A, Boolean) => Formatted): Option[Formatted] = {\n      tpe match {\n        case Refined(parents, decls) =>\n          def elements = sanitizeParents(parents).map(formatType(_, top))\n\n          val result = Some(RefinedForm(elements, decls.toList.map(formatDecl)))\n          result\n        case _ =>\n          None\n      }\n    }\n\n    override def diff(left: Type, right: Type, top: Boolean): Option[Formatted] =\n      (left, right) match {\n        case (Refined(leftParents, leftDecls), Refined(rightParents, rightDecls)) =>\n          val parents = compareTypes(sanitizeParents(leftParents), sanitizeParents(rightParents)).sorted\n          val decls = compareDecls(leftDecls.toList, rightDecls.toList).sorted\n          val result = Some(RefinedForm(parents, decls))\n          result\n        case _ =>\n          None\n      }\n  }\n\n  object ShapelessRecordItemFormatter extends SpecialFormatter {\n    def keyTagName = \"shapeless.labelled.KeyTag\"\n\n    def taggedName = \"shapeless.tag.Tagged\"\n\n    def isKeyTag(tpe: Type): Boolean = tpe.typeSymbol.fullName == keyTagName\n\n    def isTagged(tpe: Type): Boolean = tpe.typeSymbol.fullName == taggedName\n\n    object extractRecord {\n      def unapply(tpe: Type): Option[(global.Type, global.Type)] =\n        tpe match {\n          case RefinedType(actual :: key :: Nil, _) if isKeyTag(key) =>\n            Some((actual, key))\n          case _ =>\n            None\n        }\n    }\n\n    object extractStringConstant {\n      def unapply(tpe: Type): Option[String] =\n        tpe match {\n          case ConstantType(Constant(a: String)) =>\n            Some(a)\n          case _ =>\n            None\n        }\n    }\n\n    def formatConstant(tag: String): PartialFunction[Type, String] = {\n      case a if a == typeOf[scala.Symbol] =>\n        s\"'$tag\"\n    }\n\n    def formatKeyArg: PartialFunction[List[Type], Option[Formatted]] = {\n      case RefinedType(parents, _) :: _ :: Nil =>\n        for {\n          main <- parents.headOption\n          tagged <- parents.find(isTagged)\n          headArg <- tagged.typeArgs.headOption\n          tag <- extractStringConstant.unapply(headArg)\n          repr <- formatConstant(tag).lift(main)\n        } yield Simple(repr)\n      case extractStringConstant(tag) :: _ :: Nil =>\n        Some(Simple(s\"\"\"\"$tag\"\"\"\"))\n      case tag :: _ :: Nil =>\n        Some(formatType(tag, top = true))\n    }\n\n    def formatKey(tpe: Type): Formatted = formatKeyArg.lift(tpe.typeArgs).flatten.getOrElse(formatType(tpe, top = true))\n\n    def recordItem(actual: Type, key: Type): Infix =\n      Infix(Simple(\"->>\"), formatKey(key), formatType(actual, top = true), top = false)\n\n    def diff(left: Type, right: Type, top: Boolean): Option[Formatted] =\n      left -> right match {\n        case (extractRecord(a1, k1), extractRecord(a2, k2)) =>\n          val rec: ((Formatted, Formatted), Boolean) => Formatted = {\n            case ((l, r), _) =>\n              if (l == r)\n                l\n              else\n                Diff(l, r)\n          }\n          val left = formatKey(k1) -> formatKey(k2)\n          val right = formatType(a1, top = true) -> formatType(a2, top = true)\n          Some(formatInfix(Nil, \"->>\", left, right, top)(rec))\n        case _ =>\n          None\n      }\n\n    override def apply[A](\n        tpe: Type,\n        simple: String,\n        args: List[A],\n        formattedArgs: => List[Formatted],\n        top: Boolean\n    )(rec: (A, Boolean) => Formatted): Option[Formatted] = {\n      tpe match {\n        case extractRecord(actual, key) =>\n          Some(recordItem(actual, key))\n        case _ =>\n          None\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainFormattingExtension.scala",
    "content": "package splain\n\nimport scala.annotation.tailrec\nimport scala.collection.concurrent.TrieMap\nimport scala.collection.mutable\nimport scala.collection.mutable.ArrayBuffer\nimport scala.tools.nsc.typechecker\nimport scala.tools.nsc.typechecker.splain._\n\nobject SplainFormattingExtension {\n\n  import scala.reflect.internal.TypeDebugging.AnsiColor._\n\n  val ELLIPSIS: String = \"⋮\".blue\n\n  val | = \"┃\"\n  val vertical_| = \"━━━━━━━━:\"\n}\n\ntrait SplainFormattingExtension extends typechecker.splain.SplainFormatting with SplainFormattersExtension {\n  self: SplainAnalyzer =>\n\n  import SplainFormattingExtension._\n  import global._\n  import PluginSettings._\n\n  case class SplainImplicitErrorLink(\n      fromTree: ImplicitError,\n      fromHistory: DivergentImplicitTypeError\n  ) {\n\n    val sameCandidateTree: Boolean = fromTree.candidate equalsStructure fromHistory.underlyingTree\n\n    val samePendingType: Boolean = fromTree.specifics match {\n      case ss: ImplicitErrorSpecifics.NotFound =>\n        fromHistory.pt0 =:= ss.param.tpe\n      case _ =>\n        false\n    }\n\n    val moreSpecificPendingType: Boolean = fromTree.specifics match {\n      case ss: ImplicitErrorSpecifics.NotFound =>\n        fromHistory.pt0 <:< ss.param.tpe\n      case _ =>\n        false\n    }\n\n    val sameStartingWith: Boolean = {\n      fromHistory.sym.fullLocationString == fromTree.candidate.symbol.fullLocationString\n    }\n\n    //    lazy val divergingSearchStartingWithHere: Boolean = sameStartingWith\n\n    lazy val divergingSearchDiscoveredHere: Boolean = sameCandidateTree && moreSpecificPendingType\n  }\n\n  case class SplainImplicitErrorTree(\n      error: ImplicitError,\n      children: Seq[SplainImplicitErrorTree] = Nil\n  ) {\n\n    import SplainImplicitErrorTree._\n\n    def doCollectFull(alwaysDisplayRoot: Boolean = false): Seq[NodeForShow] = {\n\n      if (children.isEmpty) Seq(NodeForShow(error, alwaysShow = true))\n      else {\n\n        Seq(NodeForShow(error, alwaysShow = alwaysDisplayRoot)) ++ {\n\n          if (children.size >= 2) children.flatMap(_.doCollectFull(true))\n          else children.flatMap(_.doCollectFull())\n        }\n      }\n    }\n\n    lazy val collectFull: Seq[NodeForShow] = doCollectFull(true)\n\n    lazy val collectCompact: Seq[NodeForShow] = {\n\n      val displayed = collectFull.zipWithIndex.filter {\n        case (v, _) =>\n          v.alwaysShow\n      }\n\n      val ellipsisIndices = displayed.map(_._2 - 1).toSet + (collectFull.size - 1)\n\n      val withEllipsis = displayed.map {\n        case (v, i) =>\n          if (!ellipsisIndices.contains(i)) v.copy(showEllipsis = true)\n          else v\n      }\n\n      withEllipsis\n    }\n\n    case class FormattedChain(\n        source: Seq[NodeForShow]\n    ) {\n\n      val toList: List[String] = {\n        val collected = source.toList\n        val baseIndent = collected.headOption.map(_.nesting).getOrElse(0)\n\n        val formatted = collected.map { v =>\n          val formatted = v.formatted\n          if (v.showEllipsis) formatted.copy(_2 = formatted._2 :+ ELLIPSIS)\n          else formatted\n        }\n\n        indentTree(formatted, baseIndent)\n      }\n\n      override lazy val toString: String = toList.mkString(\"\\n\")\n    }\n\n    object FormattedChain {\n\n      object Full extends FormattedChain(collectFull)\n\n      object Compact extends FormattedChain(collectCompact)\n\n      lazy val VimplicitsVerboseTree: Boolean = settings.VimplicitsVerboseTree.value\n      val display: FormattedChain = if (VimplicitsVerboseTree) Full else Compact\n    }\n\n    override def toString: String = FormattedChain.Full.toString\n  }\n\n  object SplainImplicitErrorTree {\n\n    case class NodeForShow(\n        error: ImplicitError,\n        alwaysShow: Boolean,\n        showEllipsis: Boolean = false\n    ) {\n\n      def nesting: RunId = error.nesting\n\n      val formatted: (String, List[String], RunId) =\n        formatNestedImplicit(error)\n    }\n\n    def fromError(\n        error: ImplicitError,\n        offsprings: List[ImplicitError]\n    ): SplainImplicitErrorTree = {\n      val topNesting = error.nesting\n\n      val children = fromChildren(\n        offsprings,\n        topNesting\n      )\n\n      SplainImplicitErrorTree(error, children)\n    }\n\n    def fromChildren(\n        offsprings: List[ImplicitError],\n        topNesting: Int\n    ): List[SplainImplicitErrorTree] = {\n\n      if (offsprings.isEmpty)\n        return Nil\n\n      val minNesting = offsprings.map(v => v.nesting).min\n\n      if (minNesting < topNesting + 1)\n        throw new SplainInternalError(\n          \"Detail: nesting level of offsprings of an implicit search tree node should be higher\"\n        )\n\n      val wII = offsprings.zipWithIndex\n\n      val childrenII = wII\n        .filter {\n          case (sub, _) =>\n            if (sub.nesting < minNesting) {\n              throw new SplainInternalError(\n                s\"Detail: Sub-node in implicit tree can only have nesting level larger than top node,\" +\n                  s\" but (${sub.nesting} < $minNesting)\"\n              )\n            }\n\n            sub.nesting == minNesting\n        }\n        .map(_._2)\n\n      val ranges = {\n\n        val seqs = (childrenII ++ Seq(offsprings.size))\n          .sliding(2)\n          .toList\n\n        seqs.map {\n          case Seq(from, until) =>\n            from -> until\n          case _ =>\n            throw new SplainInternalError(\"Detail: index should not be empty\")\n        }\n      }\n\n      val children = ranges.map { range =>\n        val _top = offsprings(range._1)\n\n        val _offsprings = offsprings.slice(range._1 + 1, range._2)\n\n        fromError(\n          _top,\n          _offsprings\n        )\n      }\n\n      mergeDuplicates(children)\n      //      children\n    }\n\n    def mergeDuplicates(children: List[SplainImplicitErrorTree]): List[SplainImplicitErrorTree] = {\n      val errors = children.map(_.error).distinct\n\n      val grouped = errors.map { ee =>\n        val group = children.filter(c => c.error == ee)\n\n        val mostSpecificError = group.head.error\n        // TODO: this old design is based on a huge hypothesis, should it be improved\n        //        val mostSpecificError = group.map(_.error).maxBy(v => v.candidate.toString.length)\n\n        val allChildren = group.flatMap(v => v.children)\n        val mergedChildren = mergeDuplicates(allChildren)\n\n        SplainImplicitErrorTree(mostSpecificError, mergedChildren)\n      }\n\n      grouped.distinctBy(v => v.FormattedChain.Full.toString) // TODO: this may lose information\n    }\n  }\n\n  object ImplicitErrorExtension {\n\n    def unapplyCandidate(e: ImplicitError): Tree = unapplyRecursively(e.candidate)\n\n    @tailrec\n    private def unapplyRecursively(tree: Tree): Tree =\n      tree match {\n        case TypeApply(fun, _) => unapplyRecursively(fun)\n        case Apply(fun, _) => unapplyRecursively(fun)\n        case a => a\n      }\n\n    def cleanCandidate(e: ImplicitError): String =\n      unapplyCandidate(e).toString match {\n        case ImplicitError.candidateRegex(suf) => suf\n        case a => a\n      }\n  }\n\n  override def formatNestedImplicit(err: ImplicitError): (String, List[String], Int) = {\n\n    val base = super.formatNestedImplicit(err)\n\n    import scala.reflect.internal.TypeDebugging.AnsiColor._\n    val candidate = ImplicitErrorExtension.cleanCandidate(err)\n    val problem = s\"${candidate.red} invalid because\"\n\n    object ImplicitErrorsInHistory {\n\n      lazy val posI: self.PositionIndex = PositionIndex(\n        err.candidate.pos\n      )\n\n      lazy val localHistoryOpt: Option[ImplicitsHistory.Local] =\n        ImplicitsHistory.currentGlobal.localByPosition.get(posI)\n\n      lazy val diverging: Seq[DivergentImplicitTypeError] = {\n\n        localHistoryOpt.toSeq.flatMap { history =>\n          history.DivergingImplicitErrors.errors\n        }\n      }\n    }\n\n    val extra = mutable.Buffer.empty[String]\n\n    extra ++= base._2\n\n    val discoveredHere = ImplicitErrorsInHistory.diverging.find { inHistory =>\n      val link = SplainImplicitErrorLink(err, inHistory)\n\n      link.divergingSearchDiscoveredHere\n    }\n\n    discoveredHere match {\n      case Some(ee) =>\n        ImplicitErrorsInHistory.localHistoryOpt.foreach { history =>\n          history.DivergingImplicitErrors.linkedErrors += ee\n        }\n\n        val text = DivergingImplicitErrorView(ee).errMsg\n\n        extra ++= text.split('\\n').filter(_.trim.nonEmpty)\n      case _ =>\n    }\n\n    (problem, extra.toList, base._3)\n  }\n\n  override def formatWithInfix[A](tpe: Type, args: List[A], top: Boolean)(rec: (A, Boolean) => Formatted): Formatted = {\n    val (path, simple) = formatSimpleType(tpe)\n    tpe.nameAndArgsString\n    lazy val formattedArgs = args.map(rec(_, true))\n    val special = formatSpecial(tpe, simple, args, formattedArgs, top)(rec)\n    special.getOrElse {\n      args match {\n        case left :: right :: Nil if isSymbolic(tpe) => formatInfix(path, simple, left, right, top)(rec)\n        case _ :: _ => Applied(Qualified(path, SimpleName(simple)), formattedArgs)\n        case _ => Qualified(path, SimpleName(simple))\n      }\n    }\n  }\n\n  override def formatImplicitError(\n      param: Symbol,\n      errors: List[ImplicitError],\n      annotationMsg: String\n  ): String = {\n\n    val msg = implicitMessage(param, annotationMsg)\n    val errorTrees = SplainImplicitErrorTree.fromChildren(errors, -1)\n\n    val errorTreesStr = errorTrees.map(_.FormattedChain.display.toString)\n\n    val addendum = errorTrees.headOption.toSeq.flatMap { head =>\n      import ImplicitsHistory._\n\n      val pos = head.error.candidate.pos\n      val localHistoryOpt = currentGlobal.localByPosition.get(PositionIndex(pos))\n      val addendum: Seq[String] = localHistoryOpt.toSeq.flatMap { history =>\n        val unlinkedMsgs = history.DivergingImplicitErrors.getUnlinkedMsgs\n\n        val unlinkedText = if (unlinkedMsgs.nonEmpty) {\n          val indented = unlinkedMsgs.flatMap { str =>\n            indentTree(List((str, Nil, 0)), 1)\n          }\n\n          Seq(\n            Messages.WARNING + \"The following reported error(s) cannot be linked to any part of the implicit search tree:\"\n          ) ++\n            indented\n\n        } else {\n          Nil\n        }\n\n        val logs = history.DivergingImplicitErrors.logs\n\n        val logsText = if (logs.nonEmpty) {\n\n          val indented = logs.flatMap { str =>\n            indentTree(List((str, Nil, 0)), 1)\n          }\n\n          Seq(Messages.WARNING + \"Implicit search may be broken:\") ++\n            indented\n\n        } else {\n          Nil\n        }\n\n        val text = unlinkedText ++ logsText\n\n        text\n      }\n\n      addendum\n    }\n\n    val components: Seq[String] =\n      Seq(\"implicit error;\") ++\n        msg ++\n        errorTreesStr ++\n        addendum\n\n    val result = components.mkString(\"\\n\")\n\n    result\n  }\n\n  override def extractArgs(tpe: Type): List[global.Type] = TypeView(tpe).extractArgs\n\n  override def stripType(tt: Type): (List[String], String) = {\n\n    val view = TypeView(tt)\n    view.path -> view.noArgShortName\n  }\n\n  // new implementation is idempotent and won't lose information\n  override def dealias(tpe: Type): Type = {\n\n    TypeView(tpe).dealias_normal\n  }\n\n  case class FormattedIndex(\n      ft: Formatted,\n      idHash: Int\n  )\n\n  object FormattedIndex {\n\n    def apply(ft: Formatted) = new FormattedIndex(\n      ft,\n      System.identityHashCode(ft)\n    )\n  }\n\n  trait Based {\n\n    def element: Formatted\n\n    protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr])\n\n    lazy val flat: String = {\n      val (header, body) = formattedHeader_Body(false)\n\n      if (body.isEmpty) header\n      else s\"$header { ${body.map(v => v.flat).mkString(\";\")} }\"\n    }\n\n    lazy val broken: Seq[String] = {\n      val (header, body) = formattedHeader_Body(true)\n      val result = indentTree(List((header, body.flatMap(_.lines).toList, 0)), 1)\n\n      result\n    }\n  }\n\n  object Based {\n\n    lazy val lookup: TrieMap[FormattedIndex, ArrayBuffer[Based]] = TrieMap.empty\n\n    // MultiMap shortcuts\n    def +=(kv: (FormattedIndex, Based)): Unit = {\n\n      lookup.getOrElseUpdate(kv._1, ArrayBuffer.empty) += kv._2\n    }\n\n    def getAll(k: FormattedIndex): List[Based] = lookup.get(k).toList.flatten\n  }\n\n  case class Reduction(\n      element: Formatted,\n      from: (String, Formatted)\n  ) extends Based {\n\n    def index(): Unit = {\n\n      if (TypeDetail.reduction.isEnabled) {\n        Based += FormattedIndex(element) -> this\n      }\n    }\n\n    override protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr]) = {\n\n      s\"(${from._1})\" -> Seq(showFormattedLImpl(from._2, break))\n    }\n  }\n\n  case class BuiltInDiffMsg(\n      element: Formatted,\n      msg: String,\n      infixOpt: Option[Formatted] = None\n  ) extends Based {\n\n    def index(): Unit = {\n\n      if (TypeDiffsDetail.`builtin-msg`.isEnabled)\n        Based += FormattedIndex(element) -> this\n    }\n\n    override protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr]) = {\n\n      lazy val infixText = infixOpt match {\n        case None => |\n        case Some(ii) => \" \" + showFormattedLImpl(ii, break).flat + \" \"\n      }\n\n      val indented = msg\n        .split(\"\\n\")\n        .filter(_ != \";\")\n\n      s\"(comparing <found>$infixText<required>)\" -> indented.toSeq.map(v => FlatType(v))\n    }\n  }\n\n  case class DefPosition(\n      element: Formatted,\n      srcInfo: String,\n      quotes: Seq[String] = Nil\n  ) extends Based {\n\n    def index(): Unit = {\n\n      if (TypeDetail.position.isEnabled)\n        Based += FormattedIndex(element) -> this\n    }\n\n    override protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr]) = {\n\n      s\"(defined at $srcInfo)\" -> quotes.map(quote => BrokenType(List(quote)))\n    }\n  }\n\n  def formatTypeRaw(tpe: Type, top: Boolean): Formatted = {\n    formatWithInfix(tpe, extractArgs(tpe), top)(formatType)\n  }\n\n  override def formatTypeImpl(tpe: Type, top: Boolean): Formatted = {\n\n    tpe.typeArgs match {\n      case List(t1, t2) =>\n        val result =\n          if (TypeDiffsDetail.disambiguation.isEnabled) {\n\n            withDisambiguation(Nil, t1, t2) {\n              formatTypeImplNoDisambiguation(tpe, top)\n            }\n          } else {\n\n            formatTypeImplNoDisambiguation(tpe, top)\n          }\n\n        result match {\n          case Infix(ii, left, right, _) =>\n            val noApparentDiff = (left == right) && (t1 != t2)\n\n            if (noApparentDiff || TypeDiffsDetail.`builtin-msg-always`.isEnabled) {\n\n              BuiltInDiffMsg(\n                result,\n                TypeDiffView(t1, t2).builtInDiffMsg,\n                Some(ii)\n              ).index()\n            }\n          case _ =>\n        }\n\n        result\n      case _ =>\n        formatTypeImplNoDisambiguation(tpe, top)\n    }\n\n  }\n\n  protected def formatTypeImplNoDisambiguation(tpe: Type, top: Boolean): Formatted = {\n    val dtpe = dealias(tpe)\n\n    val results = Seq(tpe, dtpe).distinct.map { t =>\n      formatTypeRaw(t, top)\n    }.distinct\n\n    results match {\n      case Seq(from, reduced) =>\n        Reduction(reduced, \"reduced from\" -> from).index()\n      case _ =>\n    }\n\n    val result = results.last\n\n    TypeView(tpe).defPositionOpt.foreach { v =>\n      DefPosition(\n        result,\n        v.shortText\n      ).index()\n    }\n\n    result\n  }\n\n  override def formatDiffImpl(found: Type, req: Type, top: Boolean): Formatted = {\n\n    if (TypeDiffsDetail.disambiguation.isEnabled) {\n\n      val result = withDisambiguation(Nil, found, req) {\n        formatDiffImplNoDisambiguation(found, req, top)\n      }\n\n      result match {\n        case diff: Diff =>\n          val noApparentDiff = (diff.left == diff.right) && (found != req)\n\n          if (noApparentDiff || TypeDiffsDetail.`builtin-msg-always`.isEnabled) {\n\n            BuiltInDiffMsg(\n              diff,\n              TypeDiffView(found, req).builtInDiffMsg\n            ).index()\n          }\n        case _ =>\n      }\n\n      result\n    } else {\n\n      formatDiffImplNoDisambiguation(found, req, top)\n    }\n  }\n\n  protected def formatDiffImplNoDisambiguation(found: Type, req: Type, top: Boolean): Formatted = {\n\n    val reduced = Seq(found, req).map(dealias)\n    val Seq(left, right) = reduced\n\n    if (reduced.distinct.size == 1) {\n      val only = reduced.head\n      val result = formatType(only, top)\n\n      val basedOn = Seq(found, req).distinct\n        .map { tt =>\n          formatTypeRaw(tt, top)\n        }\n        .distinct\n        .flatMap { ft =>\n          if (ft == result) None\n          else Some(\"normalized from\" -> ft)\n        }\n\n      basedOn.foreach { v =>\n        Reduction(\n          result,\n          v\n        ).index()\n      }\n\n      result\n    } else {\n      val result = {\n        val noArgs = Seq(left, right).map { tt =>\n          TypeView(tt).noArgType\n        }\n\n        if (noArgs.distinct.size == 1) {\n          formatDiffInfix(left, right, top)\n        } else {\n          formatDiffSpecial(left, right, top).getOrElse {\n\n            val result = formatDiffSimple(left, right)\n            result\n          }\n        }\n      }\n\n      val basedOn = Seq(\n        \"left side reduced from\" -> Seq(found, left),\n        \"right side reduced from\" -> Seq(req, right)\n      )\n        .flatMap {\n          case (clause, fts) =>\n            if (fts.distinct.size == 1) None\n            else {\n              val formatted = fts.map { ft =>\n                formatTypeRaw(ft, top)\n              }.distinct\n              if (formatted.size == 1) None\n              else Some(clause -> formatted.head)\n            }\n        }\n\n      basedOn.foreach { v =>\n        Reduction(\n          result,\n          v\n        ).index()\n      }\n\n      result\n    }\n  }\n\n  case class ShowFormattedHelper(break: Boolean) {\n\n    import scala.reflect.internal.TypeDebugging.AnsiColor._\n\n    def _decideBreak(flat: FlatType, broken: BrokenType): TypeRepr = {\n\n      if (break) decideBreak(flat, broken) else flat\n    }\n\n    def appendLastLine(lines: List[String], suffix: String): List[String] = {\n      lines match {\n        case Nil => List(suffix)\n        case head :: Nil => List(head + suffix)\n        case head :: tail => head :: appendLastLine(tail, suffix)\n      }\n    }\n\n    def withVerticalDelimiter(v: TypeRepr): String = {\n      v.lines\n        .map { ll =>\n          | + ll\n        }\n        .mkString(\"\\n\")\n    }\n\n    def showDiff(left: Formatted, right: Formatted): TypeRepr = {\n\n      val (ll, rr) = (left, right) match {\n        case (Qualified(lpath, lname), Qualified(rpath, rname)) if lname == rname =>\n          val prefix = lpath.reverseIterator.zip(rpath.reverseIterator).takeWhile { case (l, r) => l == r }.size + 1\n          FlatType(s\"${qualifiedName(lpath.takeRight(prefix), lname).red}\") ->\n            FlatType(s\"${qualifiedName(rpath.takeRight(prefix), rname).green}\")\n\n        case (left, right) =>\n          _showFormattedL(left) ->\n            _showFormattedL(right)\n      }\n\n      lazy val flat =\n        FlatType(s\"${ll.flat}${|}${rr.flat}\")\n\n      lazy val broken: BrokenType = {\n\n        val Seq(_ll, _rr) = Seq(ll, rr).map { v =>\n          v.indent.indent.indent.indent.indent.joinLines.trim\n        }\n\n        val result =\n          s\"\"\"\n             |found   : ${_ll}\n             |${vertical_|}\n             |required: ${_rr}\"\"\".stripMargin.trim\n\n        BrokenType(result.split(\"\\n\").toList)\n      }\n\n      val result = _decideBreak(flat, broken)\n      result\n    }\n\n    case class Tree(\n        header: String,\n        body: Seq[TypeRepr]\n    ) {\n\n      lazy val flat: String = {\n\n        if (body.isEmpty) header\n        else s\"$header { ${body.map(v => v.flat).mkString(\";\")} }\"\n      }\n\n      lazy val broken: Seq[String] = {\n        val result = indentTree(List((header, body.flatMap(_.lines).toList, 0)), 1)\n\n        result\n      }\n    }\n\n    /**\n      * If the args of an applied type constructor are multiline, create separate lines for the constructor name and the\n      * closing bracket; else return a single line.\n      */\n    def showEnclosed(\n        base: TypeRepr,\n        args: List[TypeRepr],\n        brackets: (String, String) = \"[\" -> \"]\",\n        splitter: String = \",\"\n    ): TypeRepr = {\n      val flatArgs = args.map(_.flat).mkString(brackets._1, splitter + \" \", brackets._2)\n      val flat = FlatType(s\"${base.flat}$flatArgs\")\n\n      def brokenArgs = args match {\n        case head :: tail => tail.foldLeft(head.lines)((z, a) => appendLastLine(z, splitter) ::: a.lines)\n        case _ => Nil\n      }\n\n      def broken = BrokenType(appendLastLine(base.lines, brackets._1) ::: indent(brokenArgs) ::: List(brackets._2))\n\n      _decideBreak(flat, broken)\n    }\n\n    // TODO: let Based use this?\n    def showTree(\n        base: String,\n        body: Seq[TypeRepr],\n        brackets: (String, String) = \"\" -> \"\"\n    ): TypeRepr = {\n\n      def flat = FlatType {\n\n        if (body.isEmpty) base\n        else s\"$base ${brackets._1}${body.map(v => v.flat).mkString(\";\")}${brackets._2}\"\n      }\n\n      def broken = BrokenType {\n        indentTree(List((base, body.flatMap(_.lines).toList, 0)), 1)\n      }\n\n      _decideBreak(flat, broken)\n    }\n\n    def showCompound(\n        types: List[TypeRepr],\n        infixText: String = \"with\"\n    ): TypeRepr = {\n      val infixWithSpace = s\" $infixText \"\n\n      def flat = FlatType(types.map(_.flat).mkString(infixWithSpace))\n\n      def broken = BrokenType(\n        types.map(_.lines).reduceLeft((z, a) => appendLastLine(z, infixWithSpace) ::: a)\n      )\n\n      _decideBreak(flat, broken)\n    }\n\n    def _showFormattedL(v: Formatted): TypeRepr = showFormattedL(v, break)\n\n    def showTuple(elems: List[Formatted]): TypeRepr = {\n      val formattedElems = elems.map(_showFormattedL)\n\n      elems match {\n        case List(_) =>\n          showEnclosed(FlatType(\"Tuple1\"), formattedElems)\n        case _ =>\n          showEnclosed(FlatType(\"\"), formattedElems, brackets = \"(\" -> \")\")\n      }\n    }\n\n    def apply(ft: Formatted): TypeRepr = {\n\n      val raw = ft match {\n        case Simple(name) => FlatType(name.name)\n        case Qualified(path, name) => showFormattedQualified(path, name)\n        case Applied(cons, args) => showEnclosed(_showFormattedL(cons), args.map(_showFormattedL))\n        case tpe @ Infix(_, _, _, top) =>\n          wrapParensRepr(\n            if (break) breakInfix(flattenInfix(tpe)) else FlatType(flattenInfix(tpe).map(showFormatted).mkString(\" \")),\n            top\n          )\n        case UnitForm => FlatType(\"Unit\")\n        case FunctionForm(args, ret, top) =>\n          FlatType(wrapParens(s\"${showFuncParams(args.map(showFormatted))} => ${showFormatted(ret)}\", top))\n        case TupleForm(elems) =>\n          showTuple(elems)\n\n        case RefinedForm(elems, decls) =>\n          val compound = showCompound(elems.map(_showFormattedL))\n\n          val refined =\n            if (decls.isEmpty)\n              compound\n            else if (truncateDecls(decls))\n              showEnclosed(compound, List(FlatType(\"...\")), brackets = \" {\" -> \"}\", splitter = \";\")\n            else\n              showEnclosed(compound, decls.map(_showFormattedL), brackets = \" {\" -> \"}\", splitter = \";\")\n\n          refined\n\n        case Diff(left, right) => showDiff(left, right)\n        case Decl(sym, rhs) =>\n          showTree(\n            s\"type ${showFormatted(sym)} =\",\n            Seq(_showFormattedL(rhs))\n          )\n\n        case DeclDiff(sym, left, right) =>\n          val diff = showDiff(left, right)\n          showTree(\n            s\"type ${showFormatted(sym)} =\",\n            Seq(diff)\n          )\n\n        case ByName(tpe) => FlatType(s\"(=> ${showFormatted(tpe)})\")\n      }\n\n      val index = FormattedIndex(ft)\n      val basedOn = Based.getAll(index)\n\n      val result = {\n\n        basedOn match {\n          case Nil =>\n            raw\n          case _ =>\n            def flat = FlatType(raw.flat + \" \" + basedOn.map(_.flat).mkString(\" \"))\n\n            def broken = BrokenType(raw.lines ++ basedOn.flatMap(_.broken))\n\n            raw match {\n              case _: BrokenType => broken\n              case _ => _decideBreak(flat, broken)\n            }\n        }\n      }\n\n      result\n    }\n\n  }\n\n  override def showFormattedLImpl(ft: Formatted, break: Boolean): TypeRepr = {\n    ShowFormattedHelper(break)(ft)\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainPlugin.scala",
    "content": "package splain\n\nimport scala.tools.nsc._\nimport scala.tools.nsc.typechecker.{Analyzer, MacroAnnotationNamers}\n\nclass SplainPlugin(val global: Global) extends SplainPluginLike with PluginSettings.Implicits {\n\n  override lazy val pluginSettings: PluginSettings = PluginSettings(this.opts)\n\n  lazy val splainAnalyzer: SplainAnalyzer =\n    if (global.settings.YmacroAnnotations.value)\n      new SplainAnalyzer(global, pluginSettings) with MacroAnnotationNamers\n    else\n      new SplainAnalyzer(global, pluginSettings)\n\n  {\n    val analyzerField = classOf[Global].getDeclaredField(\"analyzer\")\n    analyzerField.setAccessible(true)\n    val oldAnalyzer = analyzerField.get(global).asInstanceOf[Analyzer]\n    analyzerField.set(global, splainAnalyzer)\n\n    val phasesSetMapGetter = classOf[Global]\n      .getDeclaredMethod(\"phasesSet\")\n\n    val phasesSet = phasesSetMapGetter\n      .invoke(global)\n      .asInstanceOf[scala.collection.mutable.Set[SubComponent]]\n\n    if (phasesSet.exists(_.phaseName == \"typer\")) {\n      def subcomponentNamed(name: String) =\n        phasesSet\n          .find(_.phaseName == name)\n          .head\n      val oldScs @ List(oldNamer @ _, oldPackageobjects @ _, oldTyper @ _) = List(\n        subcomponentNamed(\"namer\"),\n        subcomponentNamed(\"packageobjects\"),\n        subcomponentNamed(\"typer\")\n      )\n      val newScs = List(splainAnalyzer.namerFactory, splainAnalyzer.packageObjects, splainAnalyzer.typerFactory)\n\n      splainAnalyzer.migrateFrom(oldAnalyzer)\n\n      phasesSet --= oldScs\n      phasesSet ++= newScs\n    }\n    // TODO: remove them after AnalyzerPlugin interface becomes stable\n  }\n\n  override def init(options: List[String], error: String => Unit): Boolean = {\n    def invalid(opt: String): Unit = error(\n      s\"splain: invalid option `$opt`, supported options are ${PluginSettings.nameToKey.map(kv => \"`\" + kv._1 + \"`\").mkString(\", \")}\"\n    )\n    def setOpt(key: String, value: String): Unit =\n      if (opts.contains(key))\n        opts.update(key, value)\n      else\n        invalid(key)\n    options.foreach { opt =>\n      opt.split(\":\").toList match {\n        case key :: value :: Nil =>\n          setOpt(key, value)\n        case key :: Nil =>\n          setOpt(key, \"true\")\n        case _ =>\n          invalid(opt)\n      }\n    }\n    PluginSettings.Keys.enabled.get\n  }\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainPluginLike.scala",
    "content": "package splain\n\nimport scala.collection.mutable\nimport scala.tools.nsc._\nimport scala.tools.nsc.plugins.PluginComponent\n\ntrait SplainPluginLike extends plugins.Plugin {\n\n  val name = \"splain\"\n  val description = \"better types and implicit errors\"\n  val components: List[PluginComponent] = Nil\n\n  val opts: mutable.Map[String, String] = PluginSettings.nameToInitValue.to(mutable.Map)\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/TyperCompatViews.scala",
    "content": "package splain\n\nimport scala.reflect.internal.util.{NoSourceFile, Position}\n\ntrait TyperCompatViews {\n  self: SplainAnalyzer =>\n\n  import global._\n\n  case class TypeView(self: Type) {\n\n    lazy val extractArgs: List[global.Type] = {\n\n      self.typeArgs\n    }\n\n    lazy val noArgType: Type = if (extractArgs.nonEmpty) {\n      self.typeConstructor\n    } else {\n      self\n    }\n\n    lazy val dealias_normal: Type = {\n\n      if (isAux(self)) self\n      else {\n        val result = self.dealias.normalize\n        result match {\n          case p: PolyType =>\n            val target = TypeView(p.resultType).dealias_normal\n            val _p = p.copy(\n              resultType = target\n            )\n            _p\n          case _ =>\n            result\n        }\n      }\n    }\n\n    lazy val definingSymbol: Symbol = {\n\n      self match {\n        case tt: SingletonType =>\n          tt.termSymbol\n        case _ =>\n          self.typeSymbolDirect\n      }\n    }\n\n    private lazy val parts = definingSymbol.ownerChain.reverse\n      .map(_.name.decodedName.toString)\n      .filterNot(part => part.startsWith(\"<\") && part.endsWith(\">\"))\n\n    lazy val (path, noArgShortName) = {\n\n      val (ownerPath, _) = parts.splitAt(Math.max(0, parts.size - 1))\n\n      val ownerPathPrefix = ownerPath.mkString(\".\")\n\n      val ttString = TypeView(noArgType).typeToString\n\n      if (ttString.startsWith(ownerPathPrefix)) {\n        ownerPath -> ttString.stripPrefix(ownerPathPrefix).stripPrefix(\".\")\n      } else {\n        Nil -> ttString\n      }\n    }\n\n    lazy val prefixFullName: String = {\n      self.prefix.typeSymbol.fullNameString\n    }\n\n    // probably not useful, withDisambiguation + longString should cover most cases\n    lazy val prefixContextIfNeeded: Option[String] = {\n\n      prefixFullName.toLowerCase match {\n        case \"<root>\" | \"<empty>\" | \"<none>\" => None\n        case _ =>\n          if (self.toLongString.startsWith(prefixFullName)) None\n          else {\n            Some(s\"(in $prefixFullName)\")\n          }\n      }\n    }\n\n    object _DefPosition {\n\n      lazy val value: Position = definingSymbol.pos\n\n      lazy val noSource: Boolean = value.source == NoSourceFile\n\n      lazy val shortText: String = {\n\n        val prefix = value.source.file.path + \":\"\n\n        val result = s\"$prefix${value.line}:${value.column}\"\n        result\n      }\n\n      lazy val formattedText: String = {\n\n        Position.formatMessage(value, \"\", shortenFile = false)\n      }\n    }\n\n    def defPositionOpt: Option[_DefPosition.type] = Option(_DefPosition).filterNot(_.noSource)\n\n    def typeToString: String = {\n\n      import PluginSettings.TypeDetail\n\n      def short = self.safeToString\n\n      val base = {\n        if (TypeDetail.long.isEnabled)\n          scala.util.Try(self.toLongString).getOrElse(short)\n        else\n          short\n      }\n\n      val extraExistential =\n        if (TypeDetail.existential.isEnabled)\n          scala.util.Try(existentialContext(self)).toOption\n        else\n          None\n\n      val extraAlias =\n        if (TypeDetail.alias.isEnabled)\n          scala.util.Try(explainAlias(self)).toOption\n        else\n          None\n\n      (Seq(base) ++ extraExistential ++ extraAlias).mkString(\"\")\n\n    }\n  }\n\n  case class TypeDiffView(\n      found: Type,\n      req: Type\n  ) {\n\n    def map(fn: Type => Type): TypeDiffView =\n      TypeDiffView(fn(found), fn(req))\n\n    def toTuple[T](fn: Type => T): (T, T) = (fn(found), fn(req))\n\n    // copied from eponymous variable in Scala compiler\n    // apparently doesn't work after type arg stripped\n//    lazy val easilyMistakable: Boolean = {\n//\n//      val foundWiden = found.widen\n//      val reqWiden = req.widen\n//      val sameNamesDifferentPrefixes =\n//        foundWiden.typeSymbol.name == reqWiden.typeSymbol.name &&\n//          foundWiden.prefix.typeSymbol != reqWiden.prefix.typeSymbol\n//      val easilyMistakable =\n//        sameNamesDifferentPrefixes &&\n//          !req.typeSymbol.isConstant &&\n//          finalOwners(foundWiden) && finalOwners(reqWiden) &&\n//          !found.typeSymbol.isTypeParameterOrSkolem && !req.typeSymbol.isTypeParameterOrSkolem\n//\n//      easilyMistakable\n//    }\n\n    lazy val builtInDiffMsg: String = {\n      val result = builtinFoundReqMsg(found, req)\n      result\n    }\n  }\n\n  case class DivergingImplicitErrorView(self: DivergentImplicitTypeError) {\n\n    lazy val errMsg: String = {\n\n      val formattedPT = showFormatted(formatType(self.pt0, top = false))\n\n      s\"diverging implicit expansion for type $formattedPT\\nstarting with ${self.sym.fullLocationString}\"\n    }\n  }\n\n  case class PositionIndex(\n      pos: Position\n  ) {}\n\n}\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/package.scala",
    "content": "import scala.tools.nsc.typechecker.splain.SimpleName\nimport scala.language.implicitConversions\n\npackage object splain {\n\n  implicit def asSimpleName(s: String): SimpleName = SimpleName(s)\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/builtin/BasicSpec/__direct/check",
    "content": "newSource1.scala:13: error: implicit error;\n!I e: ImplicitChain.II\nImplicitChain.g invalid because\n!I impPar3: ImplicitChain.I1\n――ImplicitChain.i1 invalid because\n  !I impPar7: ImplicitChain.I3\n  implicitly[II]\n            ^\nnewSource1.scala:6: error: type mismatch;\n  FoundReq.L┃FoundReq.R\n  f(new L)\n    ^\nnewSource1.scala:13: error: type mismatch;\n  Long.VeryLong[\n    Long.VeryLong[\n      found   : Long.VeryLong[\n                  Long.VeryLong[\n                    Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]\n                  ]\n                ]\n      ━━━━━━━━:\n      required: Long.VeryLong2[\n                  Long.VeryLong[\n                    Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]\n                  ]\n                ]\n    ]\n  ]\n  val str: Req = ??? : Found\n                     ^\nnewSource1.scala:4: error: implicit error;\n!I e:\n  Long.VeryLong[\n    Long.VeryLong[\n      Long.VeryLong[\n        Long.VeryLong[\n          Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]\n        ]\n      ]\n    ]\n  ]\n  implicitly[VeryLong[\n            ^\nnewSource1.scala:7: error: type mismatch;\n  Compound.y.type┃String\n  f(y)\n    ^\nnewSource1.scala:10: error: type mismatch;\n  Compound.T┃<none> with Int┃String\n  f(z)\n    ^\nnewSource1.scala:4: error: implicit error;\n!I e:\n  Long.VeryLong[\n    Long.VeryLong[\n      Long.VeryLong[\n        Long.VeryLong[\n          Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]\n        ]\n      ]\n    ]\n  ] {\n    type A = Int;\n    type B = Int;\n    type C = Int;\n    type D = Int;\n    type E = Int;\n    type F = Int;\n    type G = Int;\n    type H = Int\n  }\n  implicitly[VeryLong[\n            ^\nnewSource1.scala:4: error: implicit error;\n!I e:\n  (\n    Long.VeryLong[Int],\n    Long.VeryLong[\n      Long.VeryLong[\n        Long.VeryLong[\n          Long.VeryLong[\n            Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[Int]]]]\n          ]\n        ]\n      ]\n    ]\n  )\n  implicitly[\n            ^\nnewSource1.scala:16: error: type mismatch;\n  (\n    Long.VeryLong[Int],\n    Long.VeryLong[\n      Long.VeryLong[\n        Long.VeryLong[\n          Long.VeryLong[\n            Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[Int┃String]]]]\n          ]\n        ]\n      ]\n    ]\n  )\n  ) = x\n      ^\nnewSource1.scala:11: error: type mismatch;\n  B.this.t1.type┃B.this.t.TT\n    val t2: t.TT = t1\n                   ^\nnewSource1.scala:7: error: implicit error;\n!I e: Bounds.F[Bounds.Arg]\nBounds.g invalid because\nnonconformant bounds;\n[Bounds.Arg, Nothing]\n[A <: Bounds.Base, B]\n  implicitly[F[Arg]]\n            ^\nnewSource1.scala:4: error: implicit error;\n!I ec: scala.concurrent.ExecutionContext\n  Cannot find an implicit ExecutionContext. You might add\n  an (implicit ec: ExecutionContext) parameter to your method.\n\n  The ExecutionContext is used to configure how and on which\n  thread pools asynchronous tasks (such as Futures) will run,\n  so the specific ExecutionContext that is selected is important.\n\n  If your application does not define an ExecutionContext elsewhere,\n  consider using Scala's global ExecutionContext by defining\n  the following:\n\n  implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global\n\n  long\n  ^\nnewSource1.scala:10: error: implicit error;\n!I e: String\nf invalid because\n!I impPar4:\n  List[\n    (\n      InfixBreak.VeryLongTypeName ::::\n      InfixBreak.VeryLongTypeName ::::\n      InfixBreak.VeryLongTypeName ::::\n      InfixBreak.VeryLongTypeName\n    )\n    ::::\n    (InfixBreak.Short :::: InfixBreak.Short) ::::\n    (\n      InfixBreak.VeryLongTypeName ::::\n      InfixBreak.VeryLongTypeName ::::\n      InfixBreak.VeryLongTypeName ::::\n      InfixBreak.VeryLongTypeName\n    )\n    ::::\n    InfixBreak.VeryLongTypeName ::::\n    InfixBreak.VeryLongTypeName ::::\n    InfixBreak.VeryLongTypeName ::::\n    InfixBreak.VeryLongTypeName\n  ]\n   (No implicit view available from Int => InfixBreak.T2.)\n\n  implicitly[String]\n            ^\nnewSource1.scala:11: error: implicit error;\n!I e: DeepHole.C1[[Z]DeepHole.C2[DeepHole.T1,DeepHole.T2,Z]]\n  implicitly[C1[T3]]\n            ^\nnewSource1.scala:9: error: implicit error;\n!I e: Aux.F.Aux[Aux.C, Aux.D]\nAux.f invalid because\n!I impPar10: Aux.C\n  implicitly[F.Aux[C, D]]\n            ^\nnewSource1.scala:11: error: type mismatch;\n  Refined.A with\n  Refined.B with\n  Refined.E┃Refined.C with\n  Refined.F┃<none> {\n    type X = Int┃String;\n    type Y = String;\n    type Z = <none>┃String\n  }\n  f(x)\n    ^\nnewSource1.scala:21: error: type mismatch;\n  Refined.E┃Refined.C with\n  Refined.F┃<none> with\n  Refined.Sub1.A with\n  Refined.Sub1.Sub2.B {\n    type X = Int┃String;\n    type Y = String;\n    type Z = <none>┃String\n  }\n      f(x)\n        ^\nnewSource1.scala:9: error: implicit error;\n!I e: Refined.Node {type T <: Int}\n  implicitly[NodeLt[Int]]\n            ^\nnewSource1.scala:11: error: type mismatch;\n  Int(1)┃Refined.Node {type T <: Int}\n  val k: NodeLt[Int] = 1\n                       ^\nnewSource1.scala:10: error: implicit error;\n!I e: Refined.Node{type T = _$2} forSome { type _$2 <: Int }\n  implicitly[NodeLt[Int]]\n            ^\nnewSource1.scala:12: error: type mismatch;\n  Int(1)┃Refined.Node{type T = _$2} forSome { type _$2 <: Int }\n  val k: NodeLt[Int] = 1\n                       ^\nnewSource1.scala:25: error: type mismatch;\n  C.X.Y.T┃B.X.Y.T\n  f(x: C.X.Y.T)\n     ^\nnewSource1.scala:6: error: type mismatch;\n  Int┃(=> Foo.A) => Foo.B\n  f(1: Int)\n     ^\nnewSource1.scala:3: error: type mismatch;\n  String┃Tuple1[String]\n  val a: Tuple1[String] = \"Tuple1\": String\n                                  ^\nnewSource1.scala:7: error: implicit error;\n!I e: SingleImp.a.type *** SingleImp.b.type\n  implicitly[a.type *** b.type]\n            ^\nnewSource1.scala:8: error: implicit error;\n!I e: a.type *** b.type\n    implicitly[a.type *** b.type]\n              ^\nnewSource1.scala:6: error: implicit error;\n!I e: a.type *** b.type\n    implicitly[a.type *** b.type]\n              ^\nnewSource1.scala:5: error: implicit error;\n!I ev: scala.math.Ordering[Object]\n  No implicit Ordering[Object] found to build a SortedSet[Object]. You may want to upcast to a Set[Int] first by calling `unsorted`.\n\nOrdering.ordered invalid because\n!I asComparable: Object => Comparable[Any]\n  No implicit view available from Object => Comparable[_ >: Object].\n\nOrdering.comparatorToOrdering invalid because\n!I cmp: java.util.Comparator[Object]\n    ms.map(_ => o)\n          ^\nnewSource1.scala:9: error: implicit error;\n!I e: List[a.TypeA]\n   (No implicit view available from Int => a.TypeA.)\n\n        implicitly[List[TypeA]]\n                  ^\nnewSource1.scala:10: error: implicit error;\n!I e: Seq[a.b.TypeB]\n   (No implicit view available from Int => a.b.TypeB.)\n\n        implicitly[Seq[TypeB]]\n                  ^\nnewSource1.scala:11: error: implicit error;\n!I e: Iterable[a.b.c.TypeC]\n        implicitly[Traversable[TypeC]]\n                  ^\nnewSource1.scala:12: error: implicit error;\n!I e: Iterator[a.b.c.d.TypeD]\n        implicitly[Iterator[TypeD]]\n                  ^\n"
  },
  {
    "path": "core/src/test/resources/splain/builtin/MaxRefinedSpec/__direct/check",
    "content": "newSource1.scala:7: error: type mismatch;\n  TruncRefined.D┃TruncRefined.C {\n    type X = TruncRefined.C;\n    type Y = TruncRefined.D\n  }\n  f(new D { type X = C; type Y = D })\n    ^\nnewSource1.scala:7: error: type mismatch;\n  TruncRefined.D┃TruncRefined.C {...}\n  f(new D { type X = C; type Y = D })\n    ^"
  },
  {
    "path": "core/src/test/resources/splain/builtin/VerboseTreeSpec/__direct/check",
    "content": "newSource1.scala:28: error: implicit error;\n!I e: tpes.I1\ni1a invalid because\n!I p: tpes.I2\n――i2 invalid because\n  !I p: tpes.I3\n――――i3a invalid because\n    !I p: tpes.I4\n――――――i4 invalid because\n      !I p: tpes.I5\n――――――――i5 invalid because\n        !I p: tpes.I6\n――――――――――i6a invalid because\n          !I p: tpes.I7\n――――――――――――i7 invalid because\n            !I p: tpes.I8\n――――――――――――――i8 invalid because\n              !I p: tpes.I9\n――――――――――i6b invalid because\n          !I p: tpes.I8\n――――――――――――i8 invalid because\n            !I p: tpes.I9\n――――i3b invalid because\n    !I p: tpes.I4\n――――――i4 invalid because\n      !I p: tpes.I5\n――――――――i5 invalid because\n        !I p: tpes.I6\n――――――――――i6a invalid because\n          !I p: tpes.I7\n――――――――――――i7 invalid because\n            !I p: tpes.I8\n――――――――――――――i8 invalid because\n              !I p: tpes.I9\n――――――――――i6b invalid because\n          !I p: tpes.I8\n――――――――――――i8 invalid because\n            !I p: tpes.I9\ni1b invalid because\n!I p: tpes.I6\n――i6a invalid because\n  !I p: tpes.I7\n――――i7 invalid because\n    !I p: tpes.I8\n――――――i8 invalid because\n      !I p: tpes.I9\n――i6b invalid because\n  !I p: tpes.I8\n――――i8 invalid because\n    !I p: tpes.I9\n  implicitly[I1]\n            ^\nnewSource1.scala:28: error: implicit error;\n!I e: tpes.I1\ni1a invalid because\n!I p: tpes.I2\n⋮\n――i3a invalid because\n  !I p: tpes.I4\n  ⋮\n――――i6a invalid because\n    !I p: tpes.I7\n    ⋮\n――――――――i8 invalid because\n        !I p: tpes.I9\n――――i6b invalid because\n    !I p: tpes.I8\n――――――i8 invalid because\n      !I p: tpes.I9\n――i3b invalid because\n  !I p: tpes.I4\n  ⋮\n――――i6a invalid because\n    !I p: tpes.I7\n    ⋮\n――――――――i8 invalid because\n        !I p: tpes.I9\n――――i6b invalid because\n    !I p: tpes.I8\n――――――i8 invalid because\n      !I p: tpes.I9\ni1b invalid because\n!I p: tpes.I6\n――i6a invalid because\n  !I p: tpes.I7\n  ⋮\n――――――i8 invalid because\n      !I p: tpes.I9\n――i6b invalid because\n  !I p: tpes.I8\n――――i8 invalid because\n    !I p: tpes.I9\n  implicitly[I1]\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ErrorsCompatSpec/byname/code.scala",
    "content": "object ByName {\n  type A\n\n  def f(\n      implicit\n      a: => A\n  ): Unit = ???\n\n  {\n    implicit val a: A = ???\n\n    f\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/ambiguous/code.scala",
    "content": "object Ambiguous {\n  implicit val c1: C = ???\n  implicit val c2: C = ???\n  implicit def f1: D = ???\n  implicit def f2: D = ???\n  implicitly[D]\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/ambiguous/error",
    "content": "ambiguous implicit values:\n both method f1 in object Ambiguous of type types.D\n and method f2 in object Ambiguous of type types.D\n match expected type types.D\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/bounds/code.scala",
    "content": "object NonconformantBounds {\n  trait F[A]\n  implicit def f[A <: C, B]: F[A] = ???\n  implicitly[F[D *** C]]\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/bounds/error",
    "content": "newSource1.scala:12: error: implicit error;\n!I e: NonconformantBounds.F[types.D *** types.C]\nNonconformantBounds.f invalid because\nnonconformant bounds;\n[types.D *** types.C, Nothing]\n[A <: types.C, B]\n  implicitly[F[D *** C]]\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/chain/code.scala",
    "content": "import shapeless.Poly1\n\nobject pol extends Poly1\n\ntrait Low {\n  trait I1\n  trait I2\n  trait I3\n  trait I4\n  trait F[X[_]]\n  implicit def lowI1: I1 = ???\n  implicit def lowI2: I2 = ???\n}\n\nobject ImplicitChain extends Low {\n  type T1 = C *** D >:< (C with D { type A = D; type B = C })\n  type T2 = D *** ((C >:< C) *** (D => Unit))\n  type T3 = (D *** (C *** String)) >:< ((C, D, C) *** D)\n  type T4 = C *** D *** C\n  type T5 = D *** C >:< D\n  type T6 = pol.Case.Aux[Int, String]\n  type T7 = D >:< C >:< D\n  implicit def i1(\n      implicit\n      impPar7: I3\n  ): I1 = ???\n  implicit def i2a(\n      implicit\n      impPar8: I3\n  ): I2 = ???\n  implicit def i2b(\n      implicit\n      impPar8: I3\n  ): I2 = ???\n  implicit def i4(\n      implicit\n      impPar9: I2\n  ): I4 = ???\n  implicit def t7(\n      implicit\n      impPar14: F[({ type λ[X] = Either[Int, X] })#λ]\n  ): T7 = ???\n  implicit def t5(\n      implicit\n      impPar13: pol.Case.Aux[Int, String]\n  ): T5 = ???\n  implicit def t4(\n      implicit\n      impPar12: T5\n  ): T4 = ???\n  implicit def t3a(\n      implicit\n      impPar11: T7\n  ): T3 = ???\n  implicit def t3b(\n      implicit\n      impPar10: T4\n  ): T3 = ???\n  implicit def f(\n      implicit\n      impPar4: I4,\n      impPar2: T3\n  ): T2 = ???\n  implicit def g(\n      implicit\n      impPar3: I1,\n      impPar1: T2\n  ): T1 = ???\n  implicitly[T1]\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/chain/error",
    "content": "newSource1.scala:77: error: implicit error;\n!I e:\n  (types.C *** types.D) >:<\n  types.C with types.D {type A = types.D; type B = types.C}\ng invalid because\n!I impPar1: types.D *** (types.C >:< types.C) *** (types.D => Unit)\n――f invalid because\n  !I impPar2:\n    (types.D *** types.C *** String) >:<\n    (types.C, types.D, types.C) ***\n    types.D\n――――t3a invalid because\n    !I impPar11: (types.D >:< types.C) >:< types.D\n――――――t7 invalid because\n      !I impPar14: ImplicitChain.F[[X]scala.util.Either[Int,X]]\n――――t3b invalid because\n    !I impPar10: (types.C *** types.D) *** types.C\n――――――t4 invalid because\n      !I impPar12: (types.D *** types.C) >:< types.D\n――――――――t5 invalid because\n        !I impPar13: pol.Case.Aux[Int, String]\n  implicitly[T1]\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/higherKindArg/code.scala",
    "content": "import shapeless.Poly1\n\nobject pol extends Poly1\n\nobject Functors {\n\n  trait F[X[_]]\n\n  implicitly[F[({ type λ[X] = Either[Int, X] })#λ]]\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/higherKindArg/error",
    "content": "newSource1.scala:17: error: implicit error;\n!I e: Functors.F[[X]scala.util.Either[Int,X]]\n  implicitly[F[({ type λ[X] = Either[Int, X] })#λ]]\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/implicit-ctrl-char/code.scala",
    "content": "import annotation.implicitNotFound\n\nobject Annotation {\n\n  trait Arg\n\n  @implicitNotFound(\"A\\n   ┃ B\\n  ┃ C\")\n  trait F[A]\n\n  trait G[A]\n\n  implicit def f[A](\n      implicit\n      ev: F[A]\n  ): G[A] = ???\n\n  implicitly[G[Arg]]\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/implicit-ctrl-char/error",
    "content": "newSource1.scala:25: error: implicit error;\n!I e: Annotation.G[Annotation.Arg]\nAnnotation.f invalid because\n!I ev: Annotation.F[Annotation.Arg]\n  A\n     ┃ B\n    ┃ C\n\n  implicitly[G[Arg]]\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/lazy/code.scala",
    "content": "import shapeless._\nimport shapeless.ops.hlist._\n\nobject LazyImp {\n  implicit def dc(\n      implicit\n      a: C *** D\n  ): D *** C = ???\n  implicit def d(\n      implicit\n      a: D *** C\n  ): D = ???\n  implicit def c(\n      implicit\n      a: Lazy[D]\n  ): C = ???\n  implicitly[C]\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/lazy/error",
    "content": "newSource1.scala:25: error: implicit error;\n!I e: types.C\nc invalid because\n!I a: shapeless.Lazy[types.D]\n  could not find Lazy implicit value of type types.D\n\n――d invalid because\n  !I a: types.D *** types.C\n――――dc invalid because\n    !I a: types.C *** types.D\n  implicitly[C]\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/member/code.scala",
    "content": "object NotAMember {\n  val a = new (C *** D >:< D *** C)\n  a.attr\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/member/error",
    "content": "newSource1.scala:11: error: value attr is not a member of types.C *** types.D >:< types.D *** types.C\n  a.attr\n    ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/lazyImplicit/code.scala",
    "content": "import shapeless.Lazy\n\nobject DivergingImplicits {\n\n  type C\n  type D\n\n  object Diverging {\n\n    trait ::[A, B]\n\n    implicit def f[A, B](\n        implicit\n        ii: Lazy[Int]\n    ): A :: B = ???\n\n    implicitly[C :: D]\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/lazyImplicit/error",
    "content": "newSource1.scala:25: error: implicit error;\n!I e: DivergingImplicits.C :: DivergingImplicits.D\nDiverging.f invalid because\n!I ii: shapeless.Lazy[Int]\n  could not find Lazy implicit value of type Int\n\n    implicitly[C :: D]\n              ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/record/code.scala",
    "content": "import shapeless._\nimport shapeless.record._\nimport shapeless.syntax.singleton._\n\nobject ShapelessRecord {\n  object Key\n  object Value\n\n  type Message = Record.`'sym -> String, \"str\" -> Value.type, Key -> Int`.T\n\n  def show(message: Message) = ???\n\n  val a =\n    ('sym ->> \"value\") ::\n      (\"str\" ->> Value) ::\n      (Key ->> 42L) :: HNil\n\n  show(a)\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/record/error",
    "content": "newSource1.scala:26: error: type mismatch;\n  ('sym ->> String) ::\n  (\"str\" ->> ShapelessRecord.Value.type) ::\n  (ShapelessRecord.Key.type ->> Long┃Int) ::\n  shapeless.HNil\n  show(a)\n       ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/witness-value/code.scala",
    "content": "import shapeless._\nimport shapeless.ops.hlist._\n\nobject WitnessImp {\n  def fn[A, B](a: A, b: B)(\n      implicit\n      ev: A *** B\n  ) = ???\n\n  fn(Witness(3).value, Witness(4).value)\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/witness-value/error",
    "content": "newSource1.scala:18: error: implicit error;\n!I ev: Int(3) *** Int(4)\n  fn(Witness(3).value, Witness(4).value)\n    ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular/code.scala",
    "content": "object DivergingImplicits {\n\n  type C\n  type D\n\n  object Circular {\n    implicit def f(\n        implicit\n        c: C\n    ): D = ???\n\n    implicit def g(\n        implicit\n        d: D\n    ): C = ???\n\n    implicitly[C]\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular/error",
    "content": "newSource1.scala:17: error: implicit error;\n!I e: DivergingImplicits.C\ng invalid because\n!I d: DivergingImplicits.D\ndiverging implicit expansion for type DivergingImplicits.D\nstarting with method f in object Circular\n――f invalid because\n  !I c: DivergingImplicits.C\n――――g invalid because\n    !I d: DivergingImplicits.D\n    diverging implicit expansion for type DivergingImplicits.D\n    starting with method f in object Circular\n    implicitly[C]\n              ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular-recoverable/code.scala",
    "content": "object DivergingImplicits {\n\n  type C\n  type D\n\n  trait LowLevel {\n\n    implicit def f2: D = ???\n  }\n\n  object Circular extends LowLevel {\n    implicit def f(\n        implicit\n        c: C\n    ): D = ???\n\n    implicit def g(\n        implicit\n        d: D\n    ): C = ???\n\n    implicitly[C]\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging/code.scala",
    "content": "object DivergingImplicits {\n\n  type C\n  type D\n\n  object Diverging {\n    trait ::[A, B]\n\n    implicit def f[A, B](\n        implicit\n        ii: Int :: A :: B\n    ): A :: B = ???\n\n    implicit def g[A, B]: Int :: Int :: Int :: A :: B = ???\n\n    implicitly[C :: D]\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging/error",
    "content": "newSource1.scala:16: error: implicit error;\n!I e: DivergingImplicits.C :: DivergingImplicits.D\nDiverging.f invalid because\n!I ii: Int :: DivergingImplicits.C :: DivergingImplicits.D\n――Diverging.f invalid because\n  !I ii: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D\n  diverging implicit expansion for type (Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D)\n  starting with method f in object Diverging\n――――Diverging.f invalid because\n    !I ii: Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D\n    diverging implicit expansion for type (Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D)\n    starting with method g in object Diverging\n    implicitly[C :: D]\n              ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging-compact/code.scala",
    "content": "object DivergingImplicits {\n\n  type C\n  type D\n\n  object Diverging {\n    trait ::[A, B]\n\n    implicit def f[A, B](\n        implicit\n        ii: Int :: A :: B\n    ): A :: B = ???\n\n    implicit def g[A, B]: Int :: Int :: Int :: A :: B = ???\n\n    implicitly[C :: D]\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging-compact/error",
    "content": "newSource1.scala:16: error: implicit error;\n!I e: DivergingImplicits.C :: DivergingImplicits.D\nDiverging.f invalid because\n!I ii: Int :: DivergingImplicits.C :: DivergingImplicits.D\n⋮\n――Diverging.f invalid because\n  !I ii: Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D\n  diverging implicit expansion for type (Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D)\n  starting with method g in object Diverging\n    implicitly[C :: D]\n              ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/self/code.scala",
    "content": "object DivergingImplicits {\n\n  type C\n  type D\n\n  object Endo {\n    implicit def f(\n        implicit\n        c: C\n    ): C = ???\n\n    implicitly[C]\n  }\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/self/error",
    "content": "newSource1.scala:12: error: implicit error;\n!I e: DivergingImplicits.C\nf invalid because\n!I c: DivergingImplicits.C\ndiverging implicit expansion for type DivergingImplicits.C\nstarting with method f in object Endo\n――f invalid because\n  !I c: DivergingImplicits.C\n  diverging implicit expansion for type DivergingImplicits.C\n  starting with method f in object Endo\n    implicitly[C]\n              ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDetailPositionSpec/__direct/check",
    "content": "newSource1.scala:12: error: implicit error;\n!I e: Diff.e1.VV =:= String\n  Cannot prove that Diff.e1.VV =:= String.\n\n  implicitly[e1.VV =:= String]\n            ^\nnewSource1.scala:13: error: type mismatch;\n  String┃Diff.e1.VV\n  val x: e1.VV = ??? : String\n                     ^\nnewSource1.scala:12: error: implicit error;\n!I e: Diff.e1.VV (defined at newSource1.scala:9:10) =:= String\n  Cannot prove that Diff.e1.VV =:= String.\n\n  implicitly[e1.VV =:= String]\n            ^\nnewSource1.scala:13: error: type mismatch;\n  String┃Diff.e1.VV (defined at newSource1.scala:9:10)\n  val x: e1.VV = ??? : String\n                     ^\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDetailReductionSpec/__direct/check",
    "content": "newSource1.scala:8: error: implicit error;\n!I e: Option[Int] =:= Option[String]\n  Cannot prove that FoundReqVsImplicit.vecInt.Head =:= Option[String].\n\nimplicitly[vecInt.Head =:= Option[String]]\n          ^\nnewSource1.scala:10: error: type mismatch;\n  Option[String┃Int]\nval x: vecInt.Head = ??? : Option[String]\n                         ^\nnewSource1.scala:8: error: implicit error;\n!I e:\n  Option[Int] (reduced from) { FoundReqVsImplicit.vecInt.Head } =:=\n  Option[String]\n  Cannot prove that FoundReqVsImplicit.vecInt.Head =:= Option[String].\n\nimplicitly[vecInt.Head =:= Option[String]]\n          ^\nnewSource1.scala:10: error: type mismatch;\n  Option[String┃Int]\n  ――(right side reduced from)\n    FoundReqVsImplicit.vecInt.Head\nval x: vecInt.Head = ??? : Option[String]\n                         ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDetailSpec/__direct/check",
    "content": "\nnewSource1.scala:15: error: type mismatch;\n  Test.F[Test.a.type┃a.type]\n      wrongf(new A)(new F[AA])\n                    ^\nnewSource1.scala:16: error: implicit error;\n!I b: Test.F[a.type]\n      wrongf(new A)\n            ^\nnewSource1.scala:15: error: type mismatch;\n  Test.F[\n    found   : Test.a.type (with underlying type Test.A)\n    ━━━━━━━━:\n    required: a.type (with underlying type a.type)\n  ]\n      wrongf(new A)(new F[AA])\n                    ^\nnewSource1.scala:16: error: implicit error;\n!I b: Test.F[a.type (with underlying type a.type)]\n      wrongf(new A)\n            ^\nnewSource1.scala:15: error: type mismatch;\n  Test.F[\n    found   : Test.a.type (with underlying type Test.A)\n    ━━━━━━━━:\n    required: a.type (with underlying type a.type) where val a: Test.A\n  ]\n      wrongf(new A)(new F[AA])\n                    ^\nnewSource1.scala:16: error: implicit error;\n!I b: Test.F[a.type (with underlying type a.type) where val a: Test.A]\n      wrongf(new A)\n            ^\nnewSource1.scala:15: error: type mismatch;\n  Test.F[\n    found   : Test.a.type (with underlying type Test.A)\n    ━━━━━━━━:\n    required: a.type (with underlying type a.type) where val a: Test.A\n    ――(left side reduced from)\n      Test.AA\n  ]\n      wrongf(new A)(new F[AA])\n                    ^\nnewSource1.scala:16: error: implicit error;\n!I b: Test.F[a.type (with underlying type a.type) where val a: Test.A]\n      wrongf(new A)\n            ^\n\nnewSource1.scala:15: error: type mismatch;\n  Test.F[\n    found   : Test.a.type (with underlying type Test.A)\n              ――(defined at newSource1.scala:10:11)\n    ━━━━━━━━:\n    required: a.type (with underlying type a.type) where val a: Test.A\n              ――(defined at newSource1.scala:13:18)\n    ――(left side reduced from)\n      Test.AA\n  ]\n      wrongf(new A)(new F[AA])\n                    ^\nnewSource1.scala:16: error: implicit error;\n!I b:\n  Test.F[\n    a.type (with underlying type a.type) where val a: Test.A\n    ――(defined at newSource1.scala:13:18)\n  ]\n  ――(defined at newSource1.scala:8:13)\n      wrongf(new A)\n            ^\n\nnewSource1.scala:15: error: type mismatch;\n  Test.F[\n    found   : Test.a.type (with underlying type Test.A)\n              ――(defined at newSource1.scala:10:11)\n    ━━━━━━━━:\n    required: a.type (with underlying type a.type) where val a: Test.A\n              ――(defined at newSource1.scala:13:18)\n    ――(left side reduced from)\n      Test.AA\n    (which expands to)  Test.a.type\n  ]\n      wrongf(new A)(new F[AA])\n                    ^\nnewSource1.scala:16: error: implicit error;\n!I b:\n  Test.F[\n    a.type (with underlying type a.type) where val a: Test.A\n    ――(defined at newSource1.scala:13:18)\n  ]\n  ――(defined at newSource1.scala:8:13)\n      wrongf(new A)\n            ^\nnewSource1.scala:5: error: implicit error;\n!I e: String :: Int :: Boolean\n      implicitly[K]\n                ^\nnewSource1.scala:7: error: type mismatch;\n  String(\"abc\")┃String :: Int :: Boolean\n      def v: K = \"abc\"\n                 ^\nnewSource1.scala:5: error: implicit error;\n!I e: String :: Int :: Boolean (reduced from) { Test.K }\n      implicitly[K]\n                ^\nnewSource1.scala:7: error: type mismatch;\n  String(\"abc\")┃String :: Int :: Boolean (reduced from) { Test.K }\n  ――(right side reduced from)\n    Test.K\n      def v: K = \"abc\"\n                 ^\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDiffsDetailSpec/__direct/check",
    "content": "newSource1.scala:6: error: type mismatch;\n  Long┃Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n                    ^\nnewSource1.scala:6: error: type mismatch;\n  Long┃Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n                            ^\nnewSource1.scala:16: error: implicit error;\n!I ev: Long =:= Long\n  Cannot prove that Long =:= Long.\n\n        add2(x.head)\n            ^\nnewSource1.scala:27: error: implicit error;\n!I ev: Long <:< Long\n  Cannot prove that Long <:< Long.\n\n        add2(x.head)\n            ^\nnewSource1.scala:6: error: type mismatch;\n  Long(in method add)┃scala.Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n                    ^\nnewSource1.scala:6: error: type mismatch;\n  Long(in method add)┃scala.Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n                            ^\nnewSource1.scala:16: error: implicit error;\n!I ev: Long(in method add) =:= scala.Long\n  Cannot prove that Long =:= Long.\n\n        add2(x.head)\n            ^\nnewSource1.scala:27: error: implicit error;\n!I ev: Long(in method add) <:< scala.Long\n  Cannot prove that Long <:< Long.\n\n        add2(x.head)\n            ^\n\nnewSource1.scala:6: error: type mismatch;\n  Long(in method add)┃scala.Long\n  ――(comparing <found>┃<required>)\n     found   : Long(in method add)\n     required: scala.Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n                    ^\nnewSource1.scala:6: error: type mismatch;\n  Long(in method add)┃scala.Long\n  ――(comparing <found>┃<required>)\n     found   : Long(in method add)\n     required: scala.Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n                            ^\nnewSource1.scala:16: error: implicit error;\n!I ev:\n  Long(in method add) =:= scala.Long\n  ――(comparing <found> =:= <required>)\n     found   : Long(in method add)\n     required: scala.Long\n  Cannot prove that Long =:= Long.\n\n        add2(x.head)\n            ^\nnewSource1.scala:27: error: implicit error;\n!I ev:\n  Long(in method add) <:< scala.Long\n  ――(comparing <found> <:< <required>)\n     found   : Long(in method add)\n     required: scala.Long\n  Cannot prove that Long <:< Long.\n\n        add2(x.head)\n            ^\nnewSource1.scala:27: error: implicit error;\n!I ev:\n  Long(in method add) <:< scala.Long\n  ――(comparing <found><:<<required>)\n     found   : Long(in method add)\n     required: scala.Long\n  Cannot prove that Long <:< Long.\n\n        add2(x.head)\n            ^"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ZIOSpec/zlayer/code.scala",
    "content": "import zio._\n\nobject layers {\n\n  trait Service1\n  trait Service2\n  trait Service3\n  trait Service4\n\n  val service1 = ZLayer.succeed(new Service1 {})\n\n  val service2 = ZLayer.succeed(new Service2 {})\n\n  val service3 = ZLayer.fromService((_: Service1) => new Service3 {})\n\n  val service4 = ZLayer.succeed(new Service4 {})\n\n  val services: ULayer[Has[Service1] with Has[Service2] with Has[Service3] with Has[Service4]] =\n    service1 ++ service2 >+> service3 // ++ service4\n}\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ZIOSpec/zlayer/error",
    "content": "newSource1.scala:19: error: type mismatch;\n  zio.ZLayer[\n    Any,\n    Nothing,\n    <none>┃zio.Has[layers.Service4] with\n    zio.Has[layers.Service1] with\n    zio.Has[layers.Service2] with\n    zio.Has[layers.Service3]\n  ]\n    service1 ++ service2 >+> service3 // ++ service4\n                         ^"
  },
  {
    "path": "core/src/test/scala/splain/PlainPrettifier.scala",
    "content": "//package splain\n//\n//import org.scalactic.{Prettifier, PrettyPair}\n//\n//object PlainPrettifier extends Prettifier {\n//\n//  override def apply(o: Any): String = Prettifier.basic.apply(o)\n//\n//  override def apply(left: Any, right: Any): PrettyPair = {\n//    PrettyPair(apply(left), apply(right), None)\n//  }\n//}\n"
  },
  {
    "path": "core/src/test/scala/splain/ScalacticSpike.scala",
    "content": "//package splain\n//\n//import org.scalatest.Ignore\n//\n//@Ignore\n//class ScalacticSpike extends SpecBase {\n//\n//  it(\"can diff\") {\n//\n//    val a1 =\n//      \"\"\"\n//        |     case (s1: String, s2: String) => StringDiffer.difference(s1, s2, prettifier)\n//        |      case (s1: scala.collection.GenMap[Any, Any], s2: scala.collection.GenMap[Any, Any]) => GenMapDiffer.difference(s1, s2, prettifier)\n//        |      case (s1: scala.collection.GenSeq[_], s2: scala.collection.GenSeq[_]) => GenSeqDiffer.difference(s1, s2, prettifier)\n//        |\"\"\".stripMargin\n//\n//    val a2 =\n//      \"\"\"\n//        |     case (s1: String, s2: String) => StringDiffer.difference(s1, s2, prettifier)\n//        |      case (s1: scala.collllection.GenMap[Any, Any], s2: scala.collection.GenMap[Any, Any]) => GenMapDiffer.difference(s1, s2, prettifier)\n//        |      case (s1: scala.collection.GenSeq[_], s2: scala.collection.GenSeq[_]) => GenSeqDiffer.difference(s1, s2, prettifier)\n//        |\"\"\".stripMargin\n//\n//    val vv = PlainPrettifier.apply(a1, a2)\n//\n//    println(vv)\n//  }\n//}\n"
  },
  {
    "path": "core/src/test/scala/splain/SpecBase.scala",
    "content": "package splain\n\nimport org.scalatest.funspec.AnyFunSpec\nimport org.slf4j.LoggerFactory\n\nimport scala.util.Try\n\ntrait SpecBase extends AnyFunSpec with TestHelpers {\n\n  protected def _it: ItWord = it\n}\n\nobject SpecBase {\n\n  trait Direct extends SpecBase {\n\n    // will use reflection to discover all type `() => String` method under this instance\n    lazy val codeToName: Map[String, String] = {\n\n      val allMethods = this.getClass.getMethods\n      val methods = allMethods.filter { method =>\n        method.getParameterCount == 0 &&\n        method.getReturnType == classOf[String]\n      }\n\n      val methodSeq = methods.flatMap { method =>\n        Try {\n          val code = method.invoke(this).asInstanceOf[String]\n          code -> method.getName\n        }.toOption\n      }.toSeq\n\n      Map(methodSeq: _*)\n    }\n\n    def getName(code: String, nameOverride: String, profile: Profile = Profile.default): String = {\n      val baseName =\n        if (nameOverride.nonEmpty) nameOverride\n        else codeToName(code)\n\n      val name =\n        if (profile == Profile.default) baseName\n        else s\"$baseName - $profile\"\n\n      name\n    }\n\n    lazy val runner: DirectRunner = DirectRunner()\n\n    def check(\n        code: String,\n        profile: Profile = Profile.default,\n        nameOverride: String = \"\",\n        numberOfErrors: Int = 1,\n        verbose: Boolean = false\n    ): Unit = {\n\n      val name = getName(code, nameOverride, profile)\n\n      val cc = DirectCase(code, profile)\n\n      val from = runner.pointer.getAndAdd(numberOfErrors)\n      val until = runner.pointer.get()\n      val groundTruth = runner.groundTruths.slice(from, until).mkString(\"\\n\")\n\n      _it(name) {\n        val error = cc.compileWith.compileError()\n        error must_== groundTruth\n\n        if (verbose)\n          LoggerFactory\n            .getLogger(this.getClass)\n            .info(\n              \"\\n\" + error\n            )\n      }\n    }\n\n    def skip(\n        code: String,\n        profile: Profile = Profile.default,\n        nameOverride: String = \"\",\n        numberOfBlocks: Int = 1\n    ): Unit = {\n\n      val name = getName(code, nameOverride, profile)\n\n      runner.pointer.getAndAdd(numberOfBlocks)\n\n      ignore(name) {}\n    }\n  }\n\n  trait File extends SpecBase {\n\n    def check(\n        name: String,\n        file: String = \"\",\n        profile: Profile = Profile.default\n    )(\n        check: CheckFile\n    ): Unit = {\n\n      val _file =\n        if (file.isEmpty) name\n        else file\n\n      val testName = Seq(name, file).filter(_.nonEmpty).mkString(\" - \")\n\n      _it(testName) {\n\n        check(FileCase(_file, profile))\n      }\n    }\n\n    def skip(\n        name: String,\n        file: String = \"\",\n        setting: Profile = Profile.default\n    )(\n        check: CheckFile\n    ): Unit = {\n\n      val _file =\n        if (file.isEmpty) name\n        else file\n\n      val testName = Seq(name, file).filter(_.nonEmpty).mkString(\" - \")\n\n      ignore(testName) {\n\n        check(FileCase(_file, setting))\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/builtin/BasicSpec.scala",
    "content": "package splain.builtin\n\nimport splain.SpecBase\n\nclass BasicSpec extends SpecBase.Direct with BasicFixture {\n\n  check(chain)\n\n  describe(\"#121\") {\n\n    check(foundReq)\n\n    check(longFoundReq)\n  }\n\n  check(longArg)\n\n  describe(\"#34\") {\n    check(compoundDiff, numberOfErrors = 2)\n  }\n\n  describe(\"#111\") {\n\n    check(LongRefined)\n\n    check(LongTuple)\n\n    check(foundReqLongTuple)\n  }\n\n  check(foundReqSameSymbol)\n\n  check(bounds)\n\n  check(longAnnotationMessage)\n\n  check(longInfix)\n\n  check(deeplyNestedHole)\n\n  check(auxType)\n\n  check(refined1, numberOfErrors = 2)\n\n  check(refined2, numberOfErrors = 2)\n\n  check(refined3, numberOfErrors = 2)\n\n  check(disambiguateQualified)\n\n  check(bynameParam)\n\n  check(tuple1)\n\n  check(singleType)\n\n  check(singleTypeInFunction)\n\n  check(singleTypeWithFreeSymbol)\n\n  check(parameterAnnotation)\n\n  check(shorthandTypes, numberOfErrors = 4)\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/builtin/BasicXSource3Spec.scala",
    "content": "package splain.builtin\n\nclass BasicXSource3Spec extends BasicSpec {\n\n  override lazy val suiteCanonicalName: String = classOf[BasicSpec].getCanonicalName\n\n  override def defaultExtraSetting: String = \"-Xsource:3\"\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/builtin/MaxRefinedSpec.scala",
    "content": "package splain.builtin\n\nimport splain.SpecBase\n\nclass MaxRefinedSpec extends SpecBase.Direct {\n\n  def truncrefined: String = \"\"\"\nobject TruncRefined\n{\n  class C\n  trait D\n  type CAux[A] = C { type X = C; type Y = D }\n  def f(arg1: CAux[D]) = ???\n  f(new D { type X = C; type Y = D })\n}\n\n  \"\"\"\n\n  check(truncrefined)\n\n  check(truncrefined, profile = \"-Vimplicits-max-refined 5\")\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/builtin/VerboseTreeSpec.scala",
    "content": "package splain.builtin\n\nimport splain.SpecBase\n\nclass VerboseTreeSpec extends SpecBase.Direct {\n\n  def verboseTree: String = \"\"\"\nobject tpes\n{\n  trait I1\n  trait I2\n  trait I3\n  trait I4\n  trait I5\n  trait I6\n  trait I7\n  trait I8\n  trait I9\n}\nimport tpes._\n\nobject Tree\n{\n  implicit def i8(implicit p: I9): I8 = ???\n  implicit def i7(implicit p: I8): I7 = ???\n  implicit def i6a(implicit p: I7): I6 = ???\n  implicit def i6b(implicit p: I8): I6 = ???\n  implicit def i5(implicit p: I6): I5 = ???\n  implicit def i4(implicit p: I5): I4 = ???\n  implicit def i3a(implicit p: I4): I3 = ???\n  implicit def i3b(implicit p: I4): I3 = ???\n  implicit def i2(implicit p: I3): I2 = ???\n  implicit def i1a(implicit p: I2): I1 = ???\n  implicit def i1b(implicit p: I6): I1 = ???\n  implicitly[I1]\n}\n  \"\"\"\n\n  check(verboseTree, profile = \"-Vimplicits-verbose-tree\")\n\n  check(verboseTree)\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/ErrorsCompatSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass ErrorsCompatSpec extends SpecBase.File {\n\n  check(\"byname\") {\n    checkSuccess()\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/PluginSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass PluginSpec extends SpecBase.File {\n\n  override def basicSetting: String = super.basicSetting + \" -Vimplicits-verbose-tree\"\n\n  override lazy val predefCode: String =\n    \"\"\"\n      |object types\n      |{\n      |  class ***[A, B]\n      |  class >:<[A, B]\n      |  class C\n      |  trait D\n      |}\n      |import types._\n      |\"\"\".stripMargin.trim\n\n  check(\"implicit resolution chains\", \"chain\") {\n    checkError()\n  }\n\n  check(\"higher kind argument\", \"higherKindArg\") {\n    checkError()\n  }\n\n  check(\"bounds\") {\n    checkError()\n  }\n\n  check(\"lazy\") {\n    checkError()\n  }\n\n  // TODO: cleanup, breakinfix is gone\n//  skip(\"linebreak long infix types\", \"break\") {\n//    checkErrorWithBreak()\n//  }\n\n//  check(\"deephole\") {\n//    checkError()\n//  }\n\n  // TODO: remove, already in TreeSpec\n//  describe(\"tree printing\") {\n//    check(\"complete\", file = \"tree\", extra = \"-Vimplicits-verbose-tree\") {\n//      checkError()\n//    }\n//\n//    skip(\"compact\", \"tree\", extra = \"-Vimplicits-verbose-tree -P:splain:compact\") {\n//      checkError(Some(\"errorCompact\"))\n//    }\n//  }\n\n  //  TODO: feature removed\n//  skip(\"prefix stripping\", \"prefix\", extra = \"-P:splain:keepmodules:2\") {\n//    checkError()\n//  }\n\n  //  TODO: feature removed\n//  skip(\"regex-rewrite\", extra = \"-P:splain:rewrite:\\\\.Level;0/5\") {\n//    checkError()\n//  }\n\n  // TODO: remove, already checked in BasicSpec\n//  check(\"refined type diff\", \"refined\") {\n//    checkError()\n//  }\n\n//  check(\"disambiguate types\", \"disambiguate\") {\n//    checkError()\n//  }\n\n  // TODO: remove, already in TruncRefinedSpec\n//  check(\"truncate refined type\", \"truncrefined\", extra = \"-Vimplicits-max-refined 10\") {\n//    checkError()\n//  }\n\n  // TODO: remove, already checked in BasicSpec\n//  check(\"byname higher order\", \"byname-higher\") {\n//    checkError()\n//  }\n\n  // TODO: remove, already checked in BasicSpec\n//  check(\"tuple1\") {\n//    checkError()\n//  }\n\n  // TODO: remove, already checked in BasicSpec\n//  describe(\"single types \") {\n//\n//    check(\"single\") {\n//      checkError()\n//    }\n//\n//    check(\"in function\", \"single-fn\") {\n//      checkError()\n//    }\n//\n//    check(\"with free symbol\", \"single-free\") {\n//      checkError()\n//    }\n//  }\n\n  check(\"not a member\", file = \"member\") {\n    checkError()\n  }\n\n  check(\"implicit annotation with control character(s)\", \"implicit-ctrl-char\") {\n    checkError()\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/ShapelessSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass ShapelessSpec extends SpecBase.File {\n\n  override def basicSetting: String = super.basicSetting + \" -Vimplicits-verbose-tree\"\n\n  override lazy val predefCode: String =\n    \"\"\"\n      |object types\n      |{\n      |  class ***[A, B]\n      |  class >:<[A, B]\n      |  class C\n      |  trait D\n      |}\n      |import types._\n      |\"\"\".stripMargin.trim\n  // in all error messages from toolbox, line number has to -8 to get the real line number\n\n  check(\"shapeless Record\", \"record\") {\n    checkError()\n  }\n\n  check(\"witness value types\", \"witness-value\") {\n    checkError()\n  }\n\n  check(\"lazyImplicit\") {\n    checkError()\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VImplicitDivergingSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VImplicitDivergingSpec extends SpecBase.File {\n\n  override def defaultExtraSetting: String = \"-Vimplicits-verbose-tree -P:splain:Vimplicits-diverging\"\n\n  check(\"self\") {\n    checkError()\n  }\n\n  check(\"circular\") {\n    checkError()\n  }\n\n  check(\n    \"... with max depth\",\n    \"circular\",\n    profile = s\"${Settings.defaultExtra} -P:splain:Vimplicits-diverging-max-depth:5\"\n  ) {\n    checkError()\n  }\n\n  check(\"circular-recoverable\") {\n    checkSuccess()\n  }\n\n  check(\n    \".... with max depth\",\n    \"circular\",\n    profile = s\"${Settings.defaultExtra} -P:splain:Vimplicits-diverging-max-depth:5\"\n  ) {\n    checkError()\n  }\n\n  check(\"diverging\") {\n    checkError()\n  }\n\n  check(\"... without verbose-tree\", \"diverging-compact\", profile = \"-P:splain:Vimplicits-diverging\") {\n    checkError()\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VImplicitDivergingXSource3Spec.scala",
    "content": "package splain.plugin\n\nclass VImplicitDivergingXSource3Spec extends VImplicitDivergingSpec {\n\n  override lazy val suiteCanonicalName: String = classOf[VImplicitDivergingSpec].getCanonicalName\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDetailPositionSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDetailPositionSpec extends SpecBase.Direct {\n\n  final val diff =\n    \"\"\"\nobject Diff {\n  class Example {\n\n    type VV\n  }\n\n  val e1 = new Example {\n\n    type VV <: Int\n  }\n\n  implicitly[e1.VV =:= String]\n  val x: e1.VV = ??? : String\n}\n  \"\"\"\n\n  describe(\"#44\") {\n\n    check(diff, numberOfErrors = 2)\n\n    check(diff, profile = \"-P:splain:Vtype-detail:position\", numberOfErrors = 2)\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDetailReductionSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDetailReductionSpec extends SpecBase.Direct {\n\n  final val foundReqVsImplicit =\n    \"\"\"\nobject FoundReqVsImplicit\n{\ntrait Vec[+T] {\n  type Head = Option[T]\n}\n\nval vecInt = new Vec[Int] {}\nimplicitly[vecInt.Head =:= Option[String]]\n\nval x: vecInt.Head = ??? : Option[String]\n}\n\"\"\"\n\n  describe(\"#101\") {\n\n    check(foundReqVsImplicit, numberOfErrors = 2)\n\n    check(foundReqVsImplicit, profile = \"-P:splain:Vtype-detail:reduction\", numberOfErrors = 2)\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDetailSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDetailSpec extends SpecBase.Direct {\n\n  final val wrongContexts =\n    \"\"\"\n    object Test {\n\n      class A {\n        class B\n        def b: B = new B\n      }\n\n      class F[T]\n\n      val a = new A\n      type AA = a.type\n\n      def wrongf(a: A)(implicit b: (F[a.type])): Unit = {}\n\n      wrongf(new A)(new F[AA])\n      wrongf(new A)\n    }\n    \"\"\"\n\n  final val reduceToInfix =\n    \"\"\"\n    object Test {\n      trait ::[A, B]\n\n      type K = String :: Int :: Boolean\n      implicitly[K]\n\n      def v: K = \"abc\"\n    }\n    \"\"\"\n\n  describe(\"#113\") {\n\n    check(wrongContexts, profile = \"-P:splain:Vtype-detail:1\", numberOfErrors = 2)\n\n    check(wrongContexts, profile = \"-P:splain:Vtype-detail:2\", numberOfErrors = 2)\n\n    check(wrongContexts, profile = \"-P:splain:Vtype-detail:3\", numberOfErrors = 2)\n\n    check(wrongContexts, profile = \"-P:splain:Vtype-detail:4\", numberOfErrors = 2)\n\n    check(wrongContexts, profile = \"-P:splain:Vtype-detail:5\", numberOfErrors = 2)\n\n    check(wrongContexts, profile = \"-P:splain:Vtype-detail:6\", numberOfErrors = 2)\n  }\n\n  describe(\"#119\") {\n\n    check(reduceToInfix, profile = \"-P:splain:Vtype-detail:3\", numberOfErrors = 2)\n\n    check(reduceToInfix, profile = \"-P:splain:Vtype-detail:4\", numberOfErrors = 2)\n  }\n\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDiffsDetailSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDiffsDetailSpec extends SpecBase.Direct {\n\n  final val diff =\n    \"\"\"\n    object Diff {\n      def add2(x:Long,y:Long): Long = x + y\n\n      def add[Long](x: List[Long], y: List[Long]): List[Long] =\n        if (x.isEmpty || y.isEmpty) Nil\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n    }\n    object DiffInEq {\n      def add2[T](y: T)(\n          implicit\n          ev: T =:= Long\n      ): Long = 1L + ev(y)\n\n      def add[Long](x: List[Long]): List[Long] = {\n\n        add2(x.head)\n      }\n    }\n    object DiffInSubtype {\n      def add2[T](y: T)(\n          implicit\n          ev: T <:< Long\n      ): Long = 1L + ev(y)\n\n      def add[Long](x: List[Long]): List[Long] = {\n\n        add2(x.head)\n      }\n    }\n\"\"\"\n\n  describe(\"#112\") {\n\n    check(diff, numberOfErrors = 4, profile = \"-P:splain:Vtype-diffs-detail:1\")\n\n    check(diff, numberOfErrors = 4, profile = \"-P:splain:Vtype-diffs-detail:2\")\n\n    check(diff, numberOfErrors = 4, profile = \"-P:splain:Vtype-diffs-detail:4\")\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/ZIOSpec.scala",
    "content": "package splain.plugin\n\nimport splain.SpecBase\n\nclass ZIOSpec extends SpecBase.File {\n\n  check(\"zlayer\") {\n    // TODO: is it still incorrect?\n    checkError()\n  }\n}\n"
  },
  {
    "path": "core/src/test/scala/splain/test/TryCompileSpec.scala",
    "content": "package splain.test\n\nimport splain.SpecBase\n\nobject TryCompileSpec {\n\n  final val successExample = {\n    \"\"\"\n    object Example\n    \"\"\"\n  }\n\n  final val parsingErrorExample = {\n    \"\"\"\n    object Example {\n    \"\"\"\n  }\n\n  class L\n  type R\n\n  final val typingErrorExample =\n    \"\"\"\n      import splain.test.TryCompileSpec._\n      \n      object FoundReq {\n        def f(r: R): Int = ???\n        f(new L)\n      }\n      \"\"\"\n\n  case class S1(i: Int)\n\n  object S1 {\n\n    implicit def default: S1 = S1(0)\n  }\n\n  case class S2(i: Int)\n\n  object S2Import {\n\n    implicit def default: S2 = S2(1)\n  }\n}\n\nclass TryCompileSpec extends SpecBase {\n\n  import TryCompileSpec._\n\n  lazy val useReflect = TryCompile.UseReflect(\"\")\n  lazy val useNSC = TryCompile.UseNSC(\"\")\n  lazy val static = TryCompile.Static()\n\n  describe(\"success\") {\n\n    val groundTruth = {\n      \"\"\"\n        |Success\n        | ---\n        |\n        |\"\"\".stripMargin\n    }\n\n    it(classOf[TryCompile.UseReflect].getName) {\n      useReflect(successExample).toString must_==\n        groundTruth\n    }\n\n    it(classOf[TryCompile.UseNSC].getName) {\n      useNSC(successExample).toString must_==\n        groundTruth\n    }\n\n    it(classOf[TryCompile.Static[_]].getName) {\n      static(successExample).toString must_==\n        groundTruth\n    }\n  }\n\n  describe(\"parsingError\") {\n\n    val groundTruth =\n      \"\"\"\n        |ParsingError\n        | ---\n        |newSource1.scala:1: error: '}' expected but eof found.\n        |object Example {\n        |                ^\n        |\"\"\".stripMargin\n\n    it(classOf[TryCompile.UseReflect].getName) {\n      useReflect(parsingErrorExample).toString must_==\n        groundTruth\n    }\n\n    it(classOf[TryCompile.UseNSC].getName) {\n      useNSC(parsingErrorExample).toString must_==\n        groundTruth\n    }\n\n    it(classOf[TryCompile.Static[_]].getName) {\n      static(parsingErrorExample).toString must_==\n        groundTruth\n    }\n  }\n\n  describe(\"typing error\") {\n\n    val groundTruth =\n      \"\"\"\n        |TypingError\n        | ---\n        |newSource1.scala:5: error: type mismatch;\n        | found   : splain.test.TryCompileSpec.L\n        | required: splain.test.TryCompileSpec.R\n        |        f(new L)\n        |          ^\n        |\"\"\".stripMargin\n\n    it(classOf[TryCompile.UseReflect].getName) {\n      useReflect(typingErrorExample).toString must_==\n        groundTruth\n    }\n\n    it(classOf[TryCompile.UseNSC].getName) {\n      useNSC(typingErrorExample).toString must_==\n        groundTruth\n    }\n\n    it(classOf[TryCompile.Static[_]].getName) {\n      static(typingErrorExample).toString must_==\n        groundTruth\n    }\n\n    it(\"... invoke implicitly\") {\n\n      object Scope extends static.FromCodeMixin {\n\n        val trial: TryCompile = typingErrorExample\n      }\n\n      Scope.trial.toString must_==\n        groundTruth\n\n    }\n  }\n\n  describe(\"runtime implicit search\") {\n\n    it(\"default scope\") {\n      val result = useReflect(\n        \"\"\"\n          |implicitly[splain.test.TryCompileSpec.S1]\n          |\"\"\".stripMargin\n      )\n\n      result match {\n        case v: TryCompile.Success#Evaluable =>\n          assert(v.issues.isEmpty)\n          assert(v.get == S1(0))\n        case v =>\n          throw new AssertionError(\"Expected success\\n\" + v)\n      }\n    }\n\n    it(\"imported scope\") {\n\n      val compiled = useReflect(\n        \"\"\"\n          |import splain.test.TryCompileSpec.S2Import._\n          |\n          |implicitly[splain.test.TryCompileSpec.S2]\n          |\"\"\".stripMargin\n      )\n\n      compiled match {\n        case v: TryCompile.Success#Evaluable =>\n          assert(v.issues.isEmpty)\n          assert(v.get == S2(1))\n        case v =>\n          throw new AssertionError(\"Expected success\\n\" + v)\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "core/src/testFixtures/scala/splain/TestHelpers.scala",
    "content": "package splain\n\nimport org.scalatest.exceptions.TestFailedException\nimport org.scalatest.{Assertion, Suite}\nimport org.slf4j.LoggerFactory\nimport splain.test.{Issue, TryCompile}\n\nimport java.nio.file.{FileSystems, Files, Path, Paths}\nimport java.util.concurrent.atomic.AtomicInteger\nimport scala.language.implicitConversions\nimport scala.util.Try\n\ntrait TestHelpers extends Suite {\n\n  import TestHelpers._\n\n  protected def basicSetting: String = \"-Vimplicits -Vtype-diffs\"\n\n  protected def defaultExtraSetting: String = \"\"\n\n  object Settings {\n\n    final lazy val basic = basicSetting\n    final lazy val defaultExtra: String = defaultExtraSetting\n  }\n\n  lazy val suiteCanonicalName: String = this.getClass.getCanonicalName\n\n  final protected lazy val resourceDir: String = suiteCanonicalName.split('.').mkString(\"/\")\n\n  def resourcePath(name: String, fname: String): Path = FileSystems.getDefault.getPath(resourceDir, name, fname)\n\n  def fileContentString(name: String, fname: String): String = {\n\n    val path = resourcePath(name, fname)\n\n    val resource = ClassLoader.getSystemClassLoader.getResource(path.toString)\n    require(resource != null, s\"Cannot find resource: $path\")\n\n    val actualPath = Paths.get(resource.toURI)\n\n    new String(Files.readAllBytes(actualPath))\n  }\n\n  def groundTruth(name: String, fname: Option[String] = None): String =\n    Try {\n      fileContentString(name, fname.getOrElse(\"error\")).stripLineEnd\n    }.recover { _: Throwable =>\n      fileContentString(name, fname.getOrElse(\"check\")).stripLineEnd\n    }.get\n\n  lazy val predefCode = \"\"\n\n  protected lazy val effectivePredef: String = {\n    val trimmed = predefCode.trim\n    if (trimmed.isEmpty) {\n      trimmed\n    } else {\n      trimmed + \"\\n\"\n    }\n  }\n\n  def getEngine(settings: String): TryCompile.Engine = {\n    //    TryCompile.UseReflect(settings)\n    TryCompile.UseNSC(settings)\n  }\n\n  sealed trait Profile {\n\n    def text: String\n  }\n\n  object Profile {\n\n    case class Splain(extraSetting: String = Settings.defaultExtra) extends Profile {\n\n      override lazy val text = s\"$enableSplainPlugin $basicSetting $extraSetting\"\n    }\n\n    case class BuiltIn(extraSetting: String = Settings.defaultExtra) extends Profile {\n\n      override lazy val text = s\"$basicSetting $extraSetting\"\n    } // use the compiler with option but no plugin\n\n    case object Disabled extends Profile {\n\n      override def text: String = \"\"\n    } // just use the plain old compiler as-is\n\n    implicit def fromString(v: String): Splain = Splain(v)\n\n    lazy val default: Splain = Splain()\n  }\n\n  class TestCase(code: String, setting: Profile) {\n\n    lazy val codeWithPredef: String = effectivePredef + code\n\n    case class CompileWith(settings: String) {\n\n      private lazy val engine = getEngine(settings)\n\n      def compile(): TryCompile = engine(codeWithPredef)\n\n      def compileError(): String =\n        compile() match {\n          case v: TryCompile.TypingError =>\n            v.Error.displayIssues\n          case TryCompile.OtherFailure(ee) =>\n            throw new AssertionError(s\"Cannot compile: $ee\", ee)\n          case ee @ _ =>\n            throw new AssertionError(s\"Type error not detected: $ee\")\n        }\n    }\n\n    def compileSuccess(): Option[String] =\n      compileWith.compile() match {\n        case _: TryCompile.Success =>\n          None\n        case v: TryCompile.Failure =>\n          Some(v.Error.displayIssues)\n      }\n\n    def checkSuccess(): Assertion =\n      assert(compileSuccess().isEmpty)\n\n    lazy val compileWith: CompileWith = CompileWith(setting.text)\n  }\n\n  implicit class SpecStringOps(self: String) {\n\n    def stripSpaceAtEnd(v: String): String = {\n\n      v.reverse.dropWhile { v =>\n        (v == ' ') || (v == '\\r')\n      }.reverse\n    }\n\n    def canonize(v: String): String = {\n      v.split('\\n').map(stripSpaceAtEnd).mkString(\"\\n\")\n    }\n\n    def must_==(groundTruth: String): Unit = {\n      val left = canonize(self)\n      val right = canonize(groundTruth)\n\n      try {\n        assert(left === right)\n      } catch {\n        case e: TestFailedException =>\n          // augmenting\n\n          val result =\n            s\"\"\"\n               |expected: <\n               |${right}\n               |> but was: <\n               |${left}\n               |>\n            \"\"\".stripMargin.trim\n\n          val ee = e.modifyMessage { _ =>\n            Some(result)\n          }\n\n          throw ee\n      }\n      ()\n    }\n  }\n\n  case class FileCase(name: String, profile: Profile = Profile.default)\n      extends TestCase(fileContentString(name, \"code.scala\"), profile) {\n\n    def checkError(errorFile: Option[String] = None): Unit = {\n\n      compileWith.compileError() must_== groundTruth(name, errorFile)\n    }\n  }\n\n  type CheckFile = FileCase => Unit\n\n  def checkError(errorFile: Option[String] = None): CheckFile = { cc =>\n    cc.compileWith.compileError() must_== groundTruth(cc.name, errorFile)\n  }\n\n  def checkErrorWithBreak(errorFile: Option[String] = None, length: Int = 20): CheckFile = { cc =>\n    val withBreak = cc.copy(profile = s\"-Vimplicits-breakinfix $length\")\n    withBreak.checkError(errorFile)\n  }\n\n  def checkSuccess(): CheckFile = { cc =>\n    assert(cc.compileSuccess().isEmpty)\n    ()\n  }\n\n  case class DirectCase(code: String, setting: Profile = Profile.default) extends TestCase(code, setting)\n\n  case class DirectRunner() {\n\n    case class ParseGroundTruths(\n        startsWith: String = Issue.defaultSrcName,\n        fName: Option[String] = None\n    ) {\n\n      lazy val raw: String = {\n\n        val gt = groundTruth(\"__direct\", fName)\n        gt\n      }\n\n      lazy val cases: Seq[String] = {\n        val regex = s\"(^|\\n)$startsWith\"\n\n        val result = raw\n          .split(\n            regex\n          )\n          .toSeq\n          .filter(_.trim.nonEmpty)\n          .map { line =>\n            (startsWith + line).trim\n          }\n\n        result\n      }\n    }\n\n    object DefaultGroundTruths extends ParseGroundTruths()\n\n    lazy val groundTruths: Seq[String] = DefaultGroundTruths.cases\n\n    val pointer = new AtomicInteger(0)\n  }\n}\n\nobject TestHelpers {\n\n  lazy val userDir: String = System.getProperty(\"user.dir\").stripSuffix(\"/\")\n\n  val plugin: String = Option(System.getProperty(\"splain.jar\")).getOrElse {\n    val dir = FileSystems.getDefault.getPath(userDir + \"/build/libs\")\n    val file =\n      Files\n        .list(dir)\n        .toArray\n        .map(v => v.asInstanceOf[Path])\n        .filter(v => v.toString.endsWith(\".jar\"))\n        .sortBy(v => v.toString)\n        .filterNot { v =>\n          Seq(\"-javadoc.jar\", \"-sources.jar\", \"-test-fixtures.jar\")\n            .map { suffix =>\n              v.toString.endsWith(suffix)\n            }\n            .exists(identity)\n        }\n        .head\n\n    LoggerFactory\n      .getLogger(this.getClass)\n      .debug(\n        s\"Using plugin jar: ${file.toString}\"\n      )\n\n    file.toAbsolutePath.toString\n  }\n\n  lazy val enableSplainPlugin: String = {\n\n    val rows = s\"\"\"\n                  |-Xplugin:$plugin\n                  |\"\"\".stripMargin.trim\n\n    rows.split('\\n').mkString(\" \")\n  }\n\n}\n"
  },
  {
    "path": "core/src/testFixtures/scala/splain/builtin/BasicFixture.scala",
    "content": "package splain.builtin\n\ntrait BasicFixture {\n\n  // from scalac tests START HERE\n  final val chain =\n    \"\"\"\nobject ImplicitChain\n{\n  trait I1\n  trait I2\n  trait I3\n  trait I4\n  trait II\n  implicit def i1(implicit impPar7: I3): I1 = ???\n  implicit def i2a(implicit impPar8: I3): I2 = ???\n  implicit def i2b(implicit impPar8: I3): I2 = ???\n  implicit def i4(implicit impPar9: I2): I4 = ???\n  implicit def g(implicit impPar3: I1, impPar1: I4): II = ???\n  implicitly[II]\n}\n  \"\"\"\n\n  final val foundReq =\n    \"\"\"\nobject FoundReq\n{\n  class L\n  type R\n  def f(r: R): Int = ???\n  f(new L)\n}\n  \"\"\"\n\n  final val longArg =\n    \"\"\"\nobject Long {\n  class VeryLong[T]\n\n  implicitly[VeryLong[\n    VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]\n  ]]\n}\n\"\"\"\n\n  final val longFoundReq =\n    \"\"\"\nobject Long {\n  class VeryLong[T]\n  class VeryLong2[T]\n\n  type Found = VeryLong[\n    VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]\n  ]\n\n  type Req = VeryLong[\n    VeryLong[VeryLong2[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]\n  ]\n\n  val str: Req = ??? : Found\n}\n\"\"\"\n\n  final val compoundDiff =\n    \"\"\"\nobject Compound {\n  trait T\n  type F[A] = A\n  def x[A](y: A): F[A with T] = y.asInstanceOf[A with T]\n  def f[A](a: A with String): F[A] = a\n  val y: F[Int with T] = x(x(1))\n  f(y)\n\n  val z: Int with T = x(x(1))\n  f(z)\n}\n    \"\"\"\n\n  final val LongRefined =\n    \"\"\"\nobject Long {\n  class VeryLong[T]\n\n  implicitly[VeryLong[\n    VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]\n  ] { type A = Int; type B = Int; type C = Int; type D = Int; type E = Int; type F = Int; type G = Int; type H = Int}]\n}\n    \"\"\"\n\n  final val LongTuple =\n    \"\"\"\nobject Long {\n  class VeryLong[T]\n\n  implicitly[\n      (\n          VeryLong[Int],\n          VeryLong[\n            VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[Int]]]]]]]\n          ]\n      )\n  ]\n}\n  \"\"\"\n\n  final val foundReqLongTuple =\n    \"\"\"\nobject Long {\n  class VeryLong[T]\n\n  val x: (\n      VeryLong[Int],\n      VeryLong[\n        VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[Int]]]]]]]\n      ]\n  ) = ???\n\n  val y: (\n      VeryLong[Int],\n      VeryLong[\n        VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]\n      ]\n  ) = x\n}\n\"\"\"\n\n  final val foundReqSameSymbol =\n    \"\"\"\nobject FoundReqSameSymbol {\n\n  trait T { type TT }\n  trait A { val t: T }\n\n  trait B {\n    val a: A\n    final val t = a.t\n\n    val t1: a.t.TT = ???\n    val t2: t.TT = t1\n  }\n}\n  \"\"\"\n\n  final val bounds =\n    \"\"\"\nobject Bounds\n{\n  trait Base\n  trait Arg\n  trait F[A]\n  implicit def g[A <: Base, B]: F[A] = ???\n  implicitly[F[Arg]]\n}\n  \"\"\"\n\n  final val longAnnotationMessage =\n    \"\"\"\nobject Long\n{\n  def long(implicit ec: scala.concurrent.ExecutionContext): Unit = ???\n  long\n}\n  \"\"\"\n\n  final val longInfix =\n    \"\"\"\nobject InfixBreak\n{\n  type ::::[A, B]\n  trait VeryLongTypeName\n  trait Short\n  type T1 = VeryLongTypeName :::: VeryLongTypeName :::: VeryLongTypeName ::::\n    VeryLongTypeName\n  type T2 = T1 :::: (Short :::: Short) :::: T1 :::: T1\n  implicit def f(implicit impPar4: List[T2]): String = ???\n  implicitly[String]\n}\n  \"\"\"\n\n  final val deeplyNestedHole =\n    \"\"\"\nobject DeepHole\n{\n  trait C1[F[_]]\n  trait C2[F[_], G[_], A]\n  trait C3[A, B]\n  trait C4[A]\n  type Id[A] = A\n  type T1[X] = C3[List[String], X]\n  type T2[Y] = C2[Id, C4, Y]\n  type T3[Z] = C2[T1, T2, Z]\n  implicitly[C1[T3]]\n}\n  \"\"\"\n\n  final val auxType =\n    \"\"\"\nobject Aux\n{\n  trait C\n  trait D\n  trait F\n  object F { type Aux[A, B] = F { type X = A; type Y = B } }\n  implicit def f[A, B](implicit impPar10: C): F { type X = A; type Y = B } =\n    ???\n  implicitly[F.Aux[C, D]]\n}\n  \"\"\"\n\n  final val refined1 =\n    \"\"\"\nobject Refined\n{\n  trait A\n  trait B\n  trait C\n  trait D\n  trait E\n  trait F\n  def f(a: A with B with C { type Y = String; type X = String; type Z = String }): Unit = ???\n  val x: B with E with A with F { type X = Int; type Y = String } = ???\n  f(x)\n\n  object Sub1 {\n    trait A\n\n    object Sub2 {\n      trait B\n\n      def f(a: A with B with C { type Y = String; type X = String; type Z = String }): Unit = ???\n      val x: B with E with A with F { type X = Int; type Y = String } = ???\n      f(x)\n    }\n  }\n}\n  \"\"\"\n\n  final val refined2 =\n    \"\"\"\nobject Refined\n{\n  trait Node {\n    type T\n  }\n\n  type NodeLt[T0] = Node {type T <: T0}\n\n  implicitly[NodeLt[Int]]\n\n  val k: NodeLt[Int] = 1\n}\n    \"\"\"\n\n  final val refined3 =\n    \"\"\"\nobject Refined\n{\n  trait Node {\n    type T\n  }\n\n  type NodeAux[T0] = Node { type T = T0 }\n  type NodeLt[T0] = NodeAux[_ <: T0]\n\n  implicitly[NodeLt[Int]]\n\n  val k: NodeLt[Int] = 1\n}\n    \"\"\"\n\n  final val disambiguateQualified =\n    \"\"\"\nobject A\n{\n  object B\n  {\n    object X\n    {\n      object Y\n      {\n        type T\n      }\n    }\n  }\n  object C\n  {\n    object X\n    {\n      object Y\n      {\n        type T\n      }\n    }\n  }\n  def f(a: B.X.Y.T): Unit = ()\n  val x: C.X.Y.T = ???\n  f(x: C.X.Y.T)\n}\n  \"\"\"\n\n  final val bynameParam =\n    \"\"\"\nobject Foo\n{\n  type A\n  type B\n  def f(g: (=> A) => B): Unit = ()\n  f(1: Int)\n}\n  \"\"\"\n\n  final val tuple1 =\n    \"\"\"\nobject Tup1\n{\n  val a: Tuple1[String] = \"Tuple1\": String\n}\n  \"\"\"\n\n  final val singleType =\n    \"\"\"\nobject SingleImp\n{\n  class ***[A, B]\n  val a = 1\n  val b = 2\n\n  implicitly[a.type *** b.type]\n}\n  \"\"\"\n\n  final val singleTypeInFunction =\n    \"\"\"\nobject SingleImp\n{\n  class ***[A, B]\n  def fn(): Unit = {\n    val a = 1\n    val b = 2\n\n    implicitly[a.type *** b.type]\n  }\n}\n  \"\"\"\n\n  final val singleTypeWithFreeSymbol =\n    \"\"\"\nobject SingleImp\n{\n  class ***[A, B]\n  def fn[A, B](a: A, b: B) = {\n\n    implicitly[a.type *** b.type]\n  }\n}\n  \"\"\"\n\n  final val parameterAnnotation =\n    \"\"\"\n  import scala.collection.mutable\n  object Test {\n    val o = new Object\n    val ms = scala.collection.mutable.SortedSet(1,2,3)\n    ms.map(_ => o)\n  }\n  \"\"\"\n  // from scalac tests END HERE\n\n  final val shorthandTypes =\n    \"\"\"\nobject a {\n  type TypeA\n  object b {\n    type TypeB\n    object c {\n      type TypeC\n      object d {\n        type TypeD\n        implicitly[List[TypeA]]\n        implicitly[Seq[TypeB]]\n        implicitly[Traversable[TypeC]]\n        implicitly[Iterator[TypeD]]\n      }\n    }\n  }\n}\n\"\"\"\n\n}\n"
  },
  {
    "path": "dev/.CI.sh",
    "content": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\necho \"[COMPILING]\" && \\\n\"${CRDIR}\"/test.sh \"${@}\"\n"
  },
  {
    "path": "dev/CI-latest.sh",
    "content": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\nARGS=${@}\n\nexec \"${CRDIR}\"/.CI.sh ${ARGS}"
  },
  {
    "path": "dev/format-code.sh",
    "content": "#!/usr/bin/env bash\n\nFWDIR=\"$(cd \"`dirname \"$0\"`\"/..; pwd)\"\n\ncd \"${FWDIR}\" || exit\n\n\"${FWDIR}\"/gradlew clean scalafix -Dorg.gradle.parallel=false\n # consumes too much memory to run in parallel\n\nscalafmt"
  },
  {
    "path": "dev/gradle-versions.sh",
    "content": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\n\n${FWDIR}/gradlew wrapper --gradle-version=8.14.3\n\n${FWDIR}/gradlew dependencyUpdates \"$@\"\n"
  },
  {
    "path": "dev/log-make-all.sh",
    "content": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\nDATE=$(date --iso-8601=second)\n\nmkdir -p ${FWDIR}/logs/compile\n\n${CRDIR}/make-all.sh --info > ${FWDIR}/logs/compile/\"$DATE\".log\n"
  },
  {
    "path": "dev/make-all.sh",
    "content": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\nDATE=$(date --iso-8601=second)\n\nmkdir -p ${FWDIR}/logs\nmkdir -p ${FWDIR}/logs/dependencyTree\n\n${FWDIR}/gradlew -q dependencyTree \"${@}\" > ${FWDIR}/logs/dependencyTree/\"$DATE\".log\n\n${FWDIR}/gradlew testClasses assemble \"${@}\"\n"
  },
  {
    "path": "dev/publish-all.sh",
    "content": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\nfor i in $(seq 9 18); do\n    echo \" [PUBLISHING] -PscalaVersion=2.13.$i\"\n    $CRDIR/publish.sh -PscalaVersion=2.13.$i\ndone"
  },
  {
    "path": "dev/publish.template.sh",
    "content": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\n\n${FWDIR}/gradlew publishToSonatype \\\n  closeSonatypeStagingRepository \\\n  -PsonatypeApiUser=??? \\\n  -PsonatypeApiKey=??? \\\n  -Psigning.gnupg.secretKey=??? \\\n  -Psigning.gnupg.passphrase=??? \\\n  \"${@}\"\n"
  },
  {
    "path": "dev/publishM2-all.sh",
    "content": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\nfor i in $(seq 9 18); do\n    echo \" [PUBLISHING] -PscalaVersion=2.13.$i\"\n    $CRDIR/publishM2.sh -PscalaVersion=2.13.$i\ndone"
  },
  {
    "path": "dev/publishM2.sh",
    "content": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\necho \"[COMPILING]\" && \\\n  \"${CRDIR}\"/../gradlew clean && \\\n  \"${CRDIR}\"/make-all.sh publishToMavenLocal \"${@}\"\n"
  },
  {
    "path": "dev/test.sh",
    "content": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\n\"${CRDIR}\"/make-all.sh \"${@}\" && \\\n${FWDIR}/gradlew test \"${@}\"\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-8.14.3-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "\nscalaGroup=org.scala-lang\n\nscalaVersion=2.13.18\n\norg.gradle.parallel=true\n#org.gradle.caching=true"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\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#      https://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# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=\"\\\\\\\"\\\\\\\"\"\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        -jar \"$APP_HOME/gradle/wrapper/gradle-wrapper.jar\" \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\n@rem you may not use this file except in compliance with the License.\n@rem You may obtain a copy of the License at\n@rem\n@rem      https://www.apache.org/licenses/LICENSE-2.0\n@rem\n@rem Unless required by applicable law or agreed to in writing, software\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n@rem See the License for the specific language governing permissions and\n@rem limitations under the License.\n@rem\n@rem SPDX-License-Identifier: Apache-2.0\n@rem\n\n@if \"%DEBUG%\"==\"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\n@rem This is normally unused\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif %ERRORLEVEL% equ 0 goto execute\n\necho. 1>&2\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\necho. 1>&2\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\necho location of your Java installation. 1>&2\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto execute\n\necho. 1>&2\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\necho. 1>&2\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\necho location of your Java installation. 1>&2\n\ngoto fail\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=\n\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" -jar \"%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\" %*\n\n:end\n@rem End local scope for the variables with windows NT shell\nif %ERRORLEVEL% equ 0 goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nset EXIT_CODE=%ERRORLEVEL%\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\nexit /b %EXIT_CODE%\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "img/VtypeDetail.md",
    "content": "XXX.scala:15: error: type mismatch;\n\n- Test.F\\[\n\n  - Test.a.type (<label class=\"ob-comment\" title=\"\" style=\"background:red\"> with underlying type Test.A <input type=\"checkbox\"> <span style=\"\"> long </span></label>)|a.type (with underlying type a.type) <label class=\"ob-comment\" title=\"\" style=\"background:orange\"> where val a: Test.A <input type=\"checkbox\"> <span style=\"\"> existential </span></label> (<label class=\"ob-comment\" title=\"\" style=\"background:yellow\"> defined at newSource1.scala:13:18 <input type=\"checkbox\"> <span style=\"\"> position </span></label>)\n\n    - <label class=\"ob-comment\" title=\"\" style=\"background:green\"> ――(left side reduced from) <input type=\"checkbox\"> <span style=\"\"> reduction </span></label>\n\n      - Test.AA  <label class=\"ob-comment\" title=\"\" style=\"background:blue\"> (which expands to)  Test.a.type <input type=\"checkbox\"> <span style=\"\"> alias </span></label>\n\n- \\]"
  },
  {
    "path": "img/VtypeDiffsDetail.md",
    "content": "XXX.scala:16: error: implicit error;\n\n- !I ev:\n\n  - Long(<label class=\"ob-comment\" title=\"\" style=\"background:red\"> in method add <input type=\"checkbox\"> <span style=\"\"> disambiguation </span></label>) =:= scala.Long\n\n  - ――(<label class=\"ob-comment\" title=\"\" style=\"background:yellow\"> comparing \\<found\\> =:= \\<required\\> <input type=\"checkbox\"> <span style=\"\"> builtIn </span></label>)\n\n    - found   : Long(in method add)\n\n    - required: scala.Long\n\n  - Cannot prove that Long =:= Long."
  },
  {
    "path": "settings.gradle.kts",
    "content": "//val versions = gradle.rootProject.versions()\n\n\ninclude(\n    \":core\",\n    \":testing:acceptance\"\n)\n\n\npluginManagement.repositories {\n    gradlePluginPortal()\n    mavenCentral()\n    // maven(\"https://dl.bintray.com/kotlin/kotlin-dev\")\n}\n"
  },
  {
    "path": "testing/acceptance/build.gradle.kts",
    "content": "val vs: Versions = versions()\n\ndependencies {\n\n    testImplementation(project(\":core\"))\n    testFixturesApi(testFixtures(project(\":core\")))\n\n    scalaCompilerPlugins(project(\":core\"))\n\n//    testImplementation(\"com.chuusai:shapeless_${vs.scalaBinaryV}:2.3.7\")\n//    testImplementation(\"dev.zio:zio_${vs.scalaBinaryV}:1.0.4\")\n}\n\ntasks {\n\n    withType<ScalaCompile> {\n\n        scalaCompileOptions.apply {\n\n            additionalParameters!!.addAll(\n                listOf(\n                    \"-Vimplicits\",\n                    \"-Vtype-diffs\",\n                    \"-P:splain:Vimplicits-diverging\"\n                )\n            )\n\n//            println(\"===== SCALAC ARGS ======\")\n//            additionalParameters!!.forEach {\n//                v ->\n//                println(v)\n//            }\n        }\n    }\n}\n"
  },
  {
    "path": "testing/acceptance/src/test/resources/splain/builtin/BasicSpec/__direct/check",
    "content": "newSource1.scala:13: error: implicit error;\n!I e: splain.acceptance.builtin.StaticBasicSpec.ImplicitChain.II\nImplicitChain.g invalid because\n!I impPar3: ImplicitChain.I1\n――ImplicitChain.i1 invalid because\n  !I impPar7: ImplicitChain.I3\n  implicitly[II]\n            ^\nnewSource1.scala:6: error: type mismatch;\n  found   : splain.acceptance.builtin.StaticBasicSpec.FoundReq.L\n  ━━━━━━━━:\n  required: splain.acceptance.builtin.StaticBasicSpec.FoundReq.R\n  f(new L)\n    ^\nnewSource1.scala:13: error: type mismatch;\n  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n      found   : splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]\n                        ]\n                      ]\n                    ]\n                  ]\n                ]\n      ━━━━━━━━:\n      required: splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong2[\n                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]\n                        ]\n                      ]\n                    ]\n                  ]\n                ]\n    ]\n  ]\n  val str: Req = ??? : Found\n                     ^\nnewSource1.scala:4: error: implicit error;\n!I e:\n  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]\n              ]\n            ]\n          ]\n        ]\n      ]\n    ]\n  ]\n  implicitly[VeryLong[\n            ^\nnewSource1.scala:7: error: type mismatch;\n  splain.acceptance.builtin.StaticBasicSpec.Compound.y.type┃String\n  f(y)\n    ^\nnewSource1.scala:4: error: implicit error;\n!I e:\n  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]\n              ]\n            ]\n          ]\n        ]\n      ]\n    ]\n  ] {\n    type A = Int;\n    type B = Int;\n    type C = Int;\n    type D = Int;\n    type E = Int;\n    type F = Int;\n    type G = Int;\n    type H = Int\n  }\n  implicitly[VeryLong[\n            ^\nnewSource1.scala:4: error: implicit error;\n!I e:\n  (\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int],\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int]\n                ]\n              ]\n            ]\n          ]\n        ]\n      ]\n    ]\n  )\n  implicitly[\n            ^\nnewSource1.scala:16: error: type mismatch;\n  (\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int],\n    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[\n                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int┃String]\n                ]\n              ]\n            ]\n          ]\n        ]\n      ]\n    ]\n  )\n  ) = x\n      ^\nnewSource1.scala:11: error: type mismatch;\n  B.this.t1.type┃B.this.t.TT\n    val t2: t.TT = t1\n                   ^\nnewSource1.scala:7: error: implicit error;\n!I e:\n  splain.acceptance.builtin.StaticBasicSpec.Bounds.F[\n    splain.acceptance.builtin.StaticBasicSpec.Bounds.Arg\n  ]\nBounds.g invalid because\nnonconformant bounds;\n[splain.acceptance.builtin.StaticBasicSpec.Bounds.Arg, Nothing]\n[A <: Bounds.Base, B]\n  implicitly[F[Arg]]\n            ^\nnewSource1.scala:4: error: implicit error;\n!I ec: scala.concurrent.ExecutionContext\n  Cannot find an implicit ExecutionContext. You might add\n  an (implicit ec: ExecutionContext) parameter to your method.\n\n  The ExecutionContext is used to configure how and on which\n  thread pools asynchronous tasks (such as Futures) will run,\n  so the specific ExecutionContext that is selected is important.\n\n  If your application does not define an ExecutionContext elsewhere,\n  consider using Scala's global ExecutionContext by defining\n  the following:\n\n  implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global\n\n  long\n  ^\nnewSource1.scala:10: error: implicit error;\n!I e: String\nf invalid because\n!I impPar4:\n  List[\n    (\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName\n    )\n    ::::\n    (\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.Short ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.Short\n    )\n    ::::\n    (\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName\n    )\n    ::::\n    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::\n    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName\n  ]\n   (No implicit view available from Int => splain.acceptance.builtin.StaticBasicSpec.InfixBreak.T2.)\n\n  implicitly[String]\n            ^\nnewSource1.scala:11: error: implicit error;\n!I e:\n  splain.acceptance.builtin.StaticBasicSpec.DeepHole.C1[\n    [Z]splain.acceptance.builtin.StaticBasicSpec.DeepHole.C2[splain.acceptance.builtin.StaticBasicSpec.DeepHole.T1,splain.acceptance.builtin.StaticBasicSpec.DeepHole.T2,Z]\n  ]\n  implicitly[C1[T3]]\n            ^\nnewSource1.scala:9: error: implicit error;\n!I e:\n  splain.acceptance.builtin.StaticBasicSpec.Aux.F.Aux[\n    splain.acceptance.builtin.StaticBasicSpec.Aux.C,\n    splain.acceptance.builtin.StaticBasicSpec.Aux.D\n  ]\nAux.f invalid because\n!I impPar10: Aux.C\n  implicitly[F.Aux[C, D]]\n            ^\nnewSource1.scala:11: error: type mismatch;\n  splain.acceptance.builtin.StaticBasicSpec.Refined.A with\n  splain.acceptance.builtin.StaticBasicSpec.Refined.B with\n  found   : splain.acceptance.builtin.StaticBasicSpec.Refined.E\n  ━━━━━━━━:\n  required: splain.acceptance.builtin.StaticBasicSpec.Refined.C with\n  splain.acceptance.builtin.StaticBasicSpec.Refined.F┃<none> {\n    type X = Int┃String;\n    type Y = String;\n    type Z = <none>┃String\n  }\n  f(x)\n    ^\nnewSource1.scala:9: error: implicit error;\n!I e: splain.acceptance.builtin.StaticBasicSpec.Refined.Node {type T <: Int}\n  implicitly[NodeLt[Int]]\n            ^\nnewSource1.scala:10: error: implicit error;\n!I e: splain.acceptance.builtin.StaticBasicSpec.Refined.Node{type T = _$1} forSome { type _$1 <: Int }\n  implicitly[NodeLt[Int]]\n            ^\nnewSource1.scala:25: error: type mismatch;\n  C.X.Y.T┃B.X.Y.T\n  f(x: C.X.Y.T)\n     ^\nnewSource1.scala:6: error: type mismatch;\n  found   : Int\n  ━━━━━━━━:\n  required: (=> splain.acceptance.builtin.StaticBasicSpec.Foo.A) => splain.acceptance.builtin.StaticBasicSpec.Foo.B\n  f(1: Int)\n     ^\nnewSource1.scala:3: error: type mismatch;\n  String┃Tuple1[String]\n  val a: Tuple1[String] = \"Tuple1\": String\n                                  ^\nnewSource1.scala:7: error: implicit error;\n!I e:\n  splain.acceptance.builtin.StaticBasicSpec.SingleImp.a.type ***\n  splain.acceptance.builtin.StaticBasicSpec.SingleImp.b.type\n  implicitly[a.type *** b.type]\n            ^\nnewSource1.scala:8: error: implicit error;\n!I e: a.type *** b.type\n    implicitly[a.type *** b.type]\n              ^\nnewSource1.scala:6: error: implicit error;\n!I e: a.type *** b.type\n    implicitly[a.type *** b.type]\n              ^\nnewSource1.scala:5: error: implicit error;\n!I ev: scala.math.Ordering[Object]\n  No implicit Ordering[Object] found to build a SortedSet[Object]. You may want to upcast to a Set[Int] first by calling `unsorted`.\n\nOrdering.ordered invalid because\n!I asComparable: Object => Comparable[Any]\n  No implicit view available from Object => Comparable[_ >: Object].\n\nOrdering.comparatorToOrdering invalid because\n!I cmp: java.util.Comparator[Object]\n    ms.map(_ => o)\n          ^\nnewSource1.scala:9: error: implicit error;\n!I e: List[splain.acceptance.builtin.StaticBasicSpec.a.TypeA]\n   (No implicit view available from Int => splain.acceptance.builtin.StaticBasicSpec.a.TypeA.)\n\n        implicitly[List[TypeA]]\n                  ^\n"
  },
  {
    "path": "testing/acceptance/src/test/scala/splain/acceptance/Acceptance.scala",
    "content": "package splain.acceptance\n\nimport org.scalatest.funspec.AnyFunSpec\nimport splain.TestHelpers\nimport splain.test.TryCompile\n\nimport scala.collection.mutable.ArrayBuffer\n\nobject Acceptance {\n\n  final val static = TryCompile.Static()\n\n  trait SpecBase extends AnyFunSpec with TestHelpers with static.FromCodeMixin {\n\n    lazy val buffer: ArrayBuffer[TryCompile] = ArrayBuffer.empty\n\n    def check(v: TryCompile, numberOfErrors: Int = 1): Unit = {\n      buffer += v\n    }\n\n    it(\"acceptance\") {\n\n      val issues = buffer.flatMap(v => v.issues).mkString(\"\\n\")\n\n      val runner = DirectRunner()\n\n      val gt = runner.DefaultGroundTruths.raw\n\n      issues must_== gt\n    }\n  }\n}\n"
  },
  {
    "path": "testing/acceptance/src/test/scala/splain/acceptance/builtin/StaticBasicSpec.scala",
    "content": "package splain.acceptance.builtin\n\nimport splain.acceptance.Acceptance\nimport splain.builtin.BasicFixture\n\nobject StaticBasicSpec {\n\n  object Delegate extends BasicFixture\n}\n\nclass StaticBasicSpec extends Acceptance.SpecBase {\n\n  override lazy val suiteCanonicalName: String = \"splain.builtin.BasicSpec\"\n\n  import StaticBasicSpec.Delegate._\n\n  check(chain)\n\n  describe(\"#121\") {\n\n    check(foundReq)\n\n    check(longFoundReq)\n  }\n\n  check(longArg)\n\n  describe(\"#34\") {\n    check(compoundDiff, numberOfErrors = 2)\n  }\n\n  describe(\"#111\") {\n\n    check(LongRefined)\n\n    check(LongTuple)\n\n    check(foundReqLongTuple)\n  }\n\n  check(foundReqSameSymbol)\n\n  check(bounds)\n\n  check(longAnnotationMessage)\n\n  check(longInfix)\n\n  check(deeplyNestedHole)\n\n  check(auxType)\n\n  check(refined1, numberOfErrors = 2)\n\n  check(refined2, numberOfErrors = 2)\n\n  check(refined3, numberOfErrors = 2)\n\n  check(disambiguateQualified)\n\n  check(bynameParam)\n\n  check(tuple1)\n\n  check(singleType)\n\n  check(singleTypeInFunction)\n\n  check(singleTypeWithFreeSymbol)\n\n  check(parameterAnnotation)\n\n  check(shorthandTypes, numberOfErrors = 4)\n}\n"
  }
]