Full Code of tek/splain for AI

master 60c92b5e6422 cached
114 files
179.8 KB
52.4k tokens
1 requests
Download .txt
Showing preview only (213K chars total). Download the full file or copy to clipboard to get everything.
Repository: tek/splain
Branch: master
Commit: 60c92b5e6422
Files: 114
Total size: 179.8 KB

Directory structure:
gitextract_4lf27vw3/

├── .gitattribute
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .scalafix.conf
├── .scalafmt.conf
├── .travis.yml
├── LICENSE
├── README.md
├── build.gradle.kts
├── buildSrc/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               ├── Versions.kt
│               └── init.kt
├── core/
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── resources/
│       │   │   └── scalac-plugin.xml
│       │   ├── scala/
│       │   │   └── splain/
│       │   │       ├── Messages.scala
│       │   │       ├── PluginSettings.scala
│       │   │       ├── SplainInternalError.scala
│       │   │       ├── format/
│       │   │       │   └── package.scala
│       │   │       └── test/
│       │   │           ├── AutoLift.scala
│       │   │           ├── CachingFrontEnd.scala
│       │   │           ├── Issue.scala
│       │   │           ├── TryCompile.scala
│       │   │           └── TryCompileMacros.scala
│       │   └── scala-2.13.7+/
│       │       └── latest/
│       │           └── splain/
│       │               ├── ImplicitsExtension.scala
│       │               ├── SplainAnalyzer.scala
│       │               ├── SplainAnalyzerShim.scala
│       │               ├── SplainFormattersExtension.scala
│       │               ├── SplainFormattingExtension.scala
│       │               ├── SplainPlugin.scala
│       │               ├── SplainPluginLike.scala
│       │               ├── TyperCompatViews.scala
│       │               └── package.scala
│       ├── test/
│       │   ├── resources/
│       │   │   └── splain/
│       │   │       ├── builtin/
│       │   │       │   ├── BasicSpec/
│       │   │       │   │   └── __direct/
│       │   │       │   │       └── check
│       │   │       │   ├── MaxRefinedSpec/
│       │   │       │   │   └── __direct/
│       │   │       │   │       └── check
│       │   │       │   └── VerboseTreeSpec/
│       │   │       │       └── __direct/
│       │   │       │           └── check
│       │   │       └── plugin/
│       │   │           ├── ErrorsCompatSpec/
│       │   │           │   └── byname/
│       │   │           │       └── code.scala
│       │   │           ├── PluginSpec/
│       │   │           │   ├── ambiguous/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── bounds/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── chain/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── higherKindArg/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── implicit-ctrl-char/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── lazy/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   └── member/
│       │   │           │       ├── code.scala
│       │   │           │       └── error
│       │   │           ├── ShapelessSpec/
│       │   │           │   ├── lazyImplicit/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── record/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   └── witness-value/
│       │   │           │       ├── code.scala
│       │   │           │       └── error
│       │   │           ├── VImplicitDivergingSpec/
│       │   │           │   ├── circular/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── circular-recoverable/
│       │   │           │   │   └── code.scala
│       │   │           │   ├── diverging/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── diverging-compact/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   └── self/
│       │   │           │       ├── code.scala
│       │   │           │       └── error
│       │   │           ├── VTypeDetailPositionSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           ├── VTypeDetailReductionSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           ├── VTypeDetailSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           ├── VTypeDiffsDetailSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           └── ZIOSpec/
│       │   │               └── zlayer/
│       │   │                   ├── code.scala
│       │   │                   └── error
│       │   └── scala/
│       │       └── splain/
│       │           ├── PlainPrettifier.scala
│       │           ├── ScalacticSpike.scala
│       │           ├── SpecBase.scala
│       │           ├── builtin/
│       │           │   ├── BasicSpec.scala
│       │           │   ├── BasicXSource3Spec.scala
│       │           │   ├── MaxRefinedSpec.scala
│       │           │   └── VerboseTreeSpec.scala
│       │           ├── plugin/
│       │           │   ├── ErrorsCompatSpec.scala
│       │           │   ├── PluginSpec.scala
│       │           │   ├── ShapelessSpec.scala
│       │           │   ├── VImplicitDivergingSpec.scala
│       │           │   ├── VImplicitDivergingXSource3Spec.scala
│       │           │   ├── VTypeDetailPositionSpec.scala
│       │           │   ├── VTypeDetailReductionSpec.scala
│       │           │   ├── VTypeDetailSpec.scala
│       │           │   ├── VTypeDiffsDetailSpec.scala
│       │           │   └── ZIOSpec.scala
│       │           └── test/
│       │               └── TryCompileSpec.scala
│       └── testFixtures/
│           └── scala/
│               └── splain/
│                   ├── TestHelpers.scala
│                   └── builtin/
│                       └── BasicFixture.scala
├── dev/
│   ├── .CI.sh
│   ├── CI-latest.sh
│   ├── format-code.sh
│   ├── gradle-versions.sh
│   ├── log-make-all.sh
│   ├── make-all.sh
│   ├── publish-all.sh
│   ├── publish.template.sh
│   ├── publishM2-all.sh
│   ├── publishM2.sh
│   └── test.sh
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── img/
│   ├── VtypeDetail.md
│   └── VtypeDiffsDetail.md
├── settings.gradle.kts
└── testing/
    └── acceptance/
        ├── build.gradle.kts
        └── src/
            └── test/
                ├── resources/
                │   └── splain/
                │       └── builtin/
                │           └── BasicSpec/
                │               └── __direct/
                │                   └── check
                └── scala/
                    └── splain/
                        └── acceptance/
                            ├── Acceptance.scala
                            └── builtin/
                                └── StaticBasicSpec.scala

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattribute
================================================
*.bat text eol=crlf
*.cmd text eol=crlf
*.java text eol=lf
*.scala text eol=lf
*.xml text eol=lf
*.py text eol=lf
*.R text eol=lf
# from apache spark

*.sh text eol=lf
* text eol=lf

================================================
FILE: .github/workflows/main.yml
================================================
name: CI

on: [push]

jobs:

  vars:
    runs-on: ubuntu-latest

    outputs:
      experimentalScalaVersions: ""

    steps:
      - name: dummy
        run: echo dummy

  build:
    needs: vars
    runs-on: ubuntu-latest

    strategy: &scala_strategy
      max-parallel: 2
      fail-fast: false
      matrix:
        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"]

    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17
      - name: Compile
        run: ./dev/publishM2.sh -PscalaVersion=${{matrix.scalaVersion}}

      - name: Pre-release on github
        uses: "marvinpinto/action-automatic-releases@latest"
        if: contains(github.ref_name, 'Release/')
        with:
          repo_token: "${{ secrets.GITHUB_TOKEN }}"
          automatic_release_tag: "${{github.ref_name}}-${{matrix.scalaVersion}}"
          title: "${{github.ref_name}}-${{matrix.scalaVersion}}"
          prerelease: true
          files: |
            LICENSE
            core/build/libs/*.jar

  test:
    needs: vars
    runs-on: ubuntu-latest

    #TODO: don't repeat yourself
    strategy: *scala_strategy

    continue-on-error: ${{ contains(needs.vars.outputs.experimentalScalaVersions, matrix.scalaVersion) }}

    steps:
      - name: debug vars
        run: echo ${{ needs.vars.outputs.experimentalScalaVersions }}
      - name: debug expression
        run: echo ${{ job.continue-on-error }}
      - uses: actions/checkout@v2
      - name: Set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      #         TODO: replica! how to remove?
      - name: Test
        run: ./dev/test.sh -PscalaVersion=${{matrix.scalaVersion}}
      - name: Publish Unit Test Results
        uses: EnricoMi/publish-unit-test-result-action@v1
        if: always()
        with:
          files: |
            **/test-results/test/*.xml
          check_name: |
            Test Report (${{matrix.scalaVersion}})


================================================
FILE: .gitignore
================================================
*.class
*.log
logs

# maven
*.versionsBackup

# gradle
**/.gradle
**/build
**/bin

# sbt
.cache/
.history/
.lib/
dist/*
target/
lib_managed/
src_managed/
project/boot/
project/plugins/project/

# Scala-IDE
.scala_dependencies
.worksheet

# Eclipse
.pmd
.classpath
.project
.settings/

# IntelliJ-IDEA
*.iml
.idea/
.idea_modules/

# VSCode
.vscode/
.obsidian/

# BSP & Metals
.bsp/
.bloop/
.metals/
**/metals.sbt

# the Singapore stack
**/.ammonite/

# Compiler
output
*/target/

#Misc
temp
**/temp
foo

#aws key
**/rootkey.csv

#publish
dev/publish.sh

================================================
FILE: .scalafix.conf
================================================
runner.dialect = scala213

// Built in rules
rules = [
  NoAutoTupling	// Rewrite that inserts explicit tuples for adapted argument lists for compatibility with -Yno-adapted-args
  NoValInForComprehension
  ProcedureSyntax
  RemoveUnused
  LeakingImplicitClassVal
  // TODO: unrealiable due to lack of speculative modification, disabled
  //  ExplicitResultTypes
]

RemoveUnused {
  imports = true
  privates = true
  locals = true
  patternvars = true
  params = true
}

ExplicitResultTypes {
  rewriteStructuralTypesToNamedSubclass = false
  skipSimpleDefinitions = false
}

================================================
FILE: .scalafmt.conf
================================================
version = "3.7.14"
runner.dialect = scala213

maxColumn = 120
lineEndings = unix

# Only format files tracked by git.
project.git = true

align {
  preset = some
  tokens = []
}

docstrings {
  blankFirstLine = true
}

newlines {
  #   topLevelStatements = [before]
  sometimesBeforeColonInMethodReturnType = false
  penalizeSingleSelectMultiArgList = false
  beforeCurlyLambdaParams = multilineWithCaseOnly
  # //  afterCurlyLambdaParams = squash
  implicitParamListModifierForce = [before, after]
}

rewrite {
  rules = [
    # //    AvoidInfix,
    Imports,
    RedundantBraces,
    RedundantParens,
    SortModifiers
  ]
  imports {
    sort=original
  }
  redundantBraces {
    generalExpressions = false
    methodBodies = false
    includeUnitMethods = false
    maxLines = 0
  }
}


================================================
FILE: .travis.yml
================================================
jdk:
  - openjdk8
language: scala
script: 'sbt splain/test'


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2016 Torsten Schmits

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# A scala compiler plugin for more concise errors

This plugin removes some of the redundancy of the compiler output and prints
additional info for implicit resolution errors.

# Versions

TL;DR

```
                 ┌──────────────────────────┐                  
                 │What's your Scala version?│                  
                 └─────────┬───────┬────────┘                  
                           │       │                           
                           │       └───────────────────┐       
                           v                           │       
    ┌─────────────────────────────────────────────┐    │       
    │                ( >= 2.13.6 )                │    │       
    │                ─────────────                │    │       
    │Do you want experimental features & bugfixes?│    │       
    └──┬───────────────┬──────────────────────────┘    │       
       │               │                               │       
       v               v                               v       
 ┌──────────┐ ┌─────────────────┐ ┌───────────────────────────┐
 │ ( yes )  │ │     ( no )      │ │( 2.12 / 2.13.0 .. 2.13.5 )│
 │ ───────  │ │     ──────      │ ├───────────────────────────┤
 │Splain 1.x│ │Compiler built-in│ │       Splain 0.5.x        │
 └──────────┘ └─────────────────┘ └───────────────────────────┘
```

### Compiler built-in

(main article: https://docs.scala-lang.org/overviews/compiler-options/index.html#Verbose_Settings)

The 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).

### v1.x (master branch)

(Only available for Scala 2.13.6+)

Splain 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.

Effectively, **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.

It is also the only branch under active development.

### v0.5.x (maintenance branch)

(Only available for Scala 2.12 and Scala 2.13.0 .. 2.13.5)

The 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**.

We strongly recommend you to upgrade to Scala 2.13.6+ to benefit from active support and up-to-date features.

### Build Matrix

| Version                          | Status                                                                                                                                                            | Compatibility                                                                    |
|----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
| 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)  |
| 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)               |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |

# Usage

### v1.x, v0.x

Include this line in your `build.sbt` (_not_ `project/plugins.sbt`!!):

```sbt
addCompilerPlugin("io.tryp" % "splain" % "0.5.8" cross CrossVersion.patch)
```

If you want to support scala versions both newer and older than `2.12.5`, use:

```sbt
libraryDependencies += {
  val v =
    if (scalaVersion.value.replaceFirst(raw"\.(\d)$$",".0$1") <= "2.12.04") "0.4.1"
    else "0.5.8"
  ("io.tryp" %% "splain" % v cross CrossVersion.patch).withConfigurations(Some("plugin->default(compile)"))
}
```

If you are using gradle with scala plugin, include this line under the dependency section of your build.gradle:

```groovy
scalaCompilerPlugins group: 'io.tryp', name: 'splain_${scalaVersion}', version: '0.5.8'
```

or build.gradle.kts:

```kotlin
scalaCompilerPlugins("io.tryp:splain_${scalaVersion}:0.5.8")
```

### compiler built-in, no plugin declaration required

Its effects however still have to be enabled in your compiler options, in minimal case, by the following 2 options (see Options for details):

```
-Vimplicits -Vtype-diffs
```

# Options

The plugin can be configured via compiler Options with the format:

| v0.x                          | built-in, v1.x       |
|:----------------------------- | -------------------- |
| `-P:splain:<param>[:<value>]` | `-<param>[:<value>]` |

`param` can be one of the following:

| v0.x              | built-in, v1.x                            | default value    |
| ----------------- |-------------------------------------------|------------------|
| `all`             | `enabled`                                 | true             |
| `infix`           | (dropped)                                 |                  |
| `foundreq`        | `Vtype-diffs`                             | false            |
| `implicits`       | `Vimplicits`                              | false            |
| `bounds`          | (dropped)                                 | false            |
| `color`           | (dropped)                                 |                  |
| `breakinfix`      | (dropped)                                 | 0                |
| `tree`            | `Vimplicits-verbose-tree`                 |                  |
| `compact`         | (dropped)                                 | false            |
| `boundsimplicits` | (dropped)                                 |                  |
| `truncrefined`    | `Vimplicits-max-refined`                  | 0                |
| `rewrite`         | (dropped)                                 | (do not rewrite) |
| `keepmodules`     | (dropped)                                 | 0                |
| (N/A)             | `P:splain:Vimplicits-diverging`           | false            |
| (N/A)             | `P:splain:Vimplicits-diverging-max-depth` | 100              |
| (N/A)             | `P:splain:Vtype-detail`                   | 1                |
| (N/A)             | `P:splain:Vtype-diffs-detail`             | 1                |


`value` can either be `true` or `false`. If omitted, the default is `true` for
both value and parameter.

The parameter `all` can be used to deactivate all features.

The parameters can be applied like this:

(in sbt)

```sbt
scalacOptions += "-P:splain:implicits:false"
```

(in gradle with scala plugin)

```kotlin
withType<ScalaCompile> {
    scalaCompileOptions.apply {
        additionalParameters = listOf("-P:splain:implicits:false")
    }
}
```

# infix types

Instead of `shapeless.::[A, HNil]`, prints `A :: HNil`.

# found/required types

Rather than printing up to four types, only the dealiased types are shown as a colored diff:

![foundreq](img/foundreq.jpg)

special consideration for `shapeless.Record`:

![foundreq_record](img/foundreq_record.jpg)

In the case of refined types in the form of `Client with Database with
Publisher`, the types will be matched with each other and a missing or surplus
type will be indicated by a `<none>` label.

# implicit resolution chains

When an implicit is not found, only the outermost error at the invocation point
is printed. This can be expanded with the compiler flag `-Xlog-implicits`, but
that also shows all invalid implicits for parameters that have been resolved
successfully.
This feature prints a compact list of all involved implicits:
![implicits](img/implicits.jpg)

Here, `!I` stands for *could not find implicit value*, the name of the implicit
parameter is in yellow, and its type in green.

If the parameter `tree` is set, the candidates will be indented according to their nesting level:

![tree](img/tree.jpg)

If the parameter `compact` is set, only the first and last implicit in a chain will be printed.

If the parameter `boundsimplicits` is set to false, any **nonconformant bounds** errors will be suppressed.

For comparison, this is the regular compiler output for this case (with
formatted types):

```
[info] unit/src/basic.scala:35: f is not a valid implicit value for
splain.ImplicitChain.T2 because:
[info] hasMatchingSymbol reported error: could not find implicit value for
parameter impPar2: (D *** (C *** String)) >:< ((C,D,C) *** D)
[info]   implicitly[T1]
[info]             ^
[info] unit/src/basic.scala:35: g is not a valid implicit value for
splain.ImplicitChain.T1 because:
[info] hasMatchingSymbol reported error: could not find implicit value for
parameter impPar1: D *** ((C >:< C) *** (D => Unit))
[info]   implicitly[T1]
[info]             ^
[error] unit/src/basic.scala:35: could not find implicit value for
parameter e: (C *** D) >:< C with D {type A = D; type B = C}
[error]   implicitly[T1]
```

# infix type and type argument line breaking

If the parameter `breakinfix` is given and greater than 0, types longer than
that number will be split into multiple lines:

```
implicit error;
!I e: String
f invalid because
!I impPar4: List[
  (
    VeryLongTypeName ::::
    VeryLongTypeName ::::
    VeryLongTypeName ::::
    VeryLongTypeName
  )
  ::::
  (Short :::: Short) ::::
  (
    VeryLongTypeName ::::
    VeryLongTypeName ::::
    VeryLongTypeName ::::
    VeryLongTypeName
  )
  ::::
  VeryLongTypeName ::::
  VeryLongTypeName ::::
  VeryLongTypeName ::::
  VeryLongTypeName
]
```

# truncating refined types

A type of the shape `T { type A = X; type B = Y }` will be displayed as `T {...}` if the parameter `truncrefined` is set
to a value `/= 0` and the refinement's length is greater than the value.

# truncating module paths

Default behaviour when printing type names is to omit the whole module path and only print the last segment.
Two options modify this behaviour:

## regex rewrite

The option `rewrite` takes a string that is parsed as a `;`-delimited list of regexes and optional replacements.

For example:

```
-P:splain:rewrite:cats\\.data/cd;.Type
```

This parses as two rewrite items:

* transform `cats.data` into `cd`
* delete all occurences of `.Type`

If a slash is present, the string following it will be used as a replacement for the matched text.
If it is absent, the empty string is substituted.

## dropping module segments by count

The option `keepmodules` determines how many segments of the module path before the type name will be displayed, but
only if the `rewrite` mechanism hasn't changed anything.

So with `-P:splain:keepmodules:2`, the qualified type `cats.free.FreeT.Suspend` will be displayed as
`free.FreeT.Suspend`, keeping the two segments `free.FreeT` before the type name.
The default is `0`, so only the type name itself will be displayed

# expanding diverging implicit errors (experimental)

A `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:

```
diverging implicit expansion for type splain.DivergingImplicits.C
starting with method f in object Circular
```

If 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):

```
implicit error;
!I e: C
f invalid because
!I c: C
diverging implicit expansion for type C
starting with method f in object Endo
――f invalid because
  !I c: C
  diverging implicit expansion for type C
  starting with method f in object Endo
```

**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.

# type detail (experimental)

The 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.

- `1` (DEFAULT) : type info in short form, by using toString (same as pre-1.1.0)
- `2` = **long** : type info in long form, by using toLongString
- `3` = `2` + (**existential** : existential context)
- `4` = `3` + (**reduction** : explain type reduction process)
- `5` = `4` + (**position** : type definition position in code)
- `6` = `5` + (**alias** : explain type aliases, this generally contains duplicate information with `3`, it is only included for completeness)

For example:

(`-P:splain:Vtype-detail:1`)

```
XXX.scala:15: error: type mismatch;
  Test.F[Test.a.type|a.type]
```

(`-P:splain:Vtype-detail:6`)

![](img/bc959e77.png)

In 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**.

# type diffs detail (experimental)

The 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.

- `1` (DEFAULT) : no augmentation (same as pre-1.1.0)
- `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
- `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)
- `4` = `3` + (**builtInAlways** : ALWAYS attach original found/required error info, even if both sides of the error message are different)

In 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**.

For example:

(`-P:splain:Vtype-diffs-detail:1`)

```
XXX.scala:16: error: implicit error;
!I ev: Long =:= Long
  Cannot prove that Long =:= Long.
```

(`-P:splain:Vtype-diffs-detail:4`)

![](img/86df485f.png)

# Development

## Bugs

Due to the nature of the hack that allows _splain_ to hook into the implicit search algorithm, other plugins using the
same trick may not work or cause _splain_ to be inactive.

Another victim of _splain_ is scaladoc – doc comments might disappear when running the task with _splain_ active, so
make sure it is disabled before doing so.

Users are encouraged to submit issues and test cases directly through pull requests, by forking the project and adding new test cases under:

| v0.x                                   | v1.x                                               |
|:-------------------------------------- | -------------------------------------------------- |
| `<project root>/src/test/scala/splain` | `<project root>/core/src/test/scala/splain/plugin` |

The 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.

## How to compile

### v1.x (from git branch master)

Built with the latest [Gradle](https://gradle.org/), to compile and publish locally:

```
./gradlew clean testClasses publishToMavenLocal
```

to run all tests:

```
./gradlew test
```


### v0.x (from git branch Maintenance/master)

Built with the latest stable [SBT](https://www.scala-sbt.org/). to compile and publish locally:

```
sbt clean publishM2
```

to run all tests:

```
sbt test
```


## How to edit

Most project contributors uses neovim, IntelliJ IDEA or visual studio code.

The 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.

## Communication

- @tek - reviewer for built-in/v0.x bugfix, new features
- @tribbloid - reviewer for v1.x bugfix
- @dwijnand - reviewer for scala compiler integration


================================================
FILE: build.gradle.kts
================================================
import org.gradle.util.internal.VersionNumber

import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask
import org.gradle.api.specs.Spec

val vs = versions()

buildscript {
    repositories {
        // Add here whatever repositories you're already using
        mavenCentral()
    }

    dependencies {
        classpath("ch.epfl.scala:gradle-bloop_2.12:1.6.4") // suffix is always 2.12, weird
    }
}

tasks.named<DependencyUpdatesTask>("dependencyUpdates").configure {
    filterConfigurations = Spec<Configuration> {
        !it.name.startsWith("incrementalScalaAnalysis")
    }
}

plugins {
    `java-test-fixtures`

    scala

    idea

    signing
    `maven-publish`
    id("io.github.gradle-nexus.publish-plugin") version "2.0.0"

    id("com.github.ben-manes.versions") version "0.53.0"

    id("io.github.cosmicsilence.scalafix") version "0.2.6"
}

val sonatypeApiUser = providers.gradleProperty("sonatypeApiUser")
val sonatypeApiKey = providers.gradleProperty("sonatypeApiKey")
if (sonatypeApiUser.isPresent && sonatypeApiKey.isPresent) {
    nexusPublishing {
        repositories {
            sonatype {

                nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
                snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/"))

                username.set(sonatypeApiUser)
                password.set(sonatypeApiKey)
//                useStaging.set(true)
            }
        }
    }
} else {
    logger.warn("Sonatype API key not defined, skipping configuration of Maven Central publishing repository")
}

allprojects {

    apply(plugin = "java-library")
    apply(plugin = "java-test-fixtures")

    // apply(plugin = "bloop")
    // DO NOT enable! In VSCode it will cause the conflict:
    // Cannot add extension with name 'bloop', as there is an extension already registered with that name

    apply(plugin = "scala")
    apply(plugin = "idea")

    apply(plugin = "signing")
    apply(plugin = "maven-publish")

    group = vs.projectGroup
    version = vs.projectV

    repositories {
        mavenCentral()
//        jcenter()
        maven("https://dl.bintray.com/kotlin/kotlin-dev")
        maven("https://scala-ci.typesafe.com/artifactory/scala-integration/") // scala SNAPSHOT
    }

    fun includeShims(from: String, to: String) {
        sourceSets {
            main {
                scala {
                    setSrcDirs(srcDirs + listOf("src/main/scala-${from}+/${to}"))
                }
                resources {
                    setSrcDirs(srcDirs + listOf("src/main/resources-${from}+/${to}"))
                }
            }
            testFixtures {
                scala {
                    setSrcDirs(srcDirs + listOf("src/testFixtures/scala-${from}+/${to}"))
                }
                resources {
                    setSrcDirs(srcDirs + listOf("src/testFixtures/resources-${from}+/${to}"))
                }
            }
            test {
                scala {
                    setSrcDirs(srcDirs + listOf("src/test/scala-${from}+/${to}"))
                }
                resources {
                    setSrcDirs(srcDirs + listOf("src/test/resources-${from}+/${to}"))
                }
            }
        }
    }

    val vn = VersionNumber.parse(vs.scala.v)
    val supportedPatchVs = 7..12

    for (from in supportedPatchVs) {
        if (vn.micro >= from) {

            includeShims("2.13.${from}", "latest")
        }
        for (to in supportedPatchVs) {
            if (vn.micro <= to) {

                includeShims("2.13.${from}", "2.13.${to}")
            }
        }
    }

    dependencies {

        constraints {}

        implementation("${vs.scala.group}:scala-library:${vs.scala.v}")

        val scalaTestV = "3.2.11"
        testFixturesApi("org.scalatest:scalatest_${vs.scala.artifactSuffix}:${scalaTestV}")
        testImplementation("org.scalatest:scalatest_${vs.scala.artifactSuffix}:${scalaTestV}")
//        testFixturesApi("org.scalatest:scalatest-core_${vs.scala.artifactSuffix}:${vs.scalaTestV}")

        val jUnitV = "5.13.4"
        val jUnitPlatformV = "1.13.4"

        testRuntimeOnly("org.junit.platform:junit-platform-engine:$jUnitPlatformV")
        testRuntimeOnly("org.junit.platform:junit-platform-launcher:$jUnitPlatformV")
        testImplementation("org.junit.jupiter:junit-jupiter:${jUnitV}")
//        testRuntimeOnly("org.scalatestplus:junit-5-13_${vs.scala.artifactSuffix}:3.2.19.0")
        testRuntimeOnly("ai.acyclic.scalatestplus:junit-5-13_${vs.scala.artifactSuffix}:3.2.19.2")
//        testRuntimeOnly("ai.acyclic.scalatestplus:junit-5-13_${vs.scala.artifactSuffix}:3.3.0.0")
    }

    tasks.register("dependencyTree") {

        dependsOn("dependencies")
    }

    val jvmTarget = JavaVersion.VERSION_1_8

    java {

        withSourcesJar()
        withJavadocJar()

        sourceCompatibility = jvmTarget
        targetCompatibility = jvmTarget
    }

    tasks {

        withType<ScalaCompile> {

            sourceCompatibility = jvmTarget.toString()
            targetCompatibility = jvmTarget.toString()

            scalaCompileOptions.apply {

//                    isForce = true

                loggingLevel = "verbose"

                val compilerOptions =

                    mutableListOf(
                        "-encoding", "UTF-8",

                        "-deprecation",
                        "-unchecked",
                        "-feature",
                        "-language:higherKinds",
                        "-language:existentials",
                        "-Ywarn-value-discard",
                        "-Ywarn-unused:imports",
                        "-Ywarn-unused:implicits",
                        "-Ywarn-unused:params",
                        "-Ywarn-unused:patvars"
//                        "-Ydebug-error"
                    )

                additionalParameters = compilerOptions

                forkOptions.apply {

                    memoryInitialSize = "1g"
                    memoryMaximumSize = "4g"

                    // this may be over the top but the test code in macro & core frequently run implicit search on church encoded Nat type
                    jvmArgs = listOf(
                        "-Xss256m"
                    )
                }
            }
        }

        test {

            minHeapSize = "1024m"
            maxHeapSize = "4096m"

            testLogging {
                showExceptions = true
                showCauses = true
                showStackTraces = true

                // stdout is used for occasional manual verification
                showStandardStreams = true
            }

//            useJUnit()
            useJUnitPlatform {
                includeEngines("scalatest")
                testLogging {
                    events("passed", "skipped", "failed")
                }
            }
        }
    }

    apply(plugin = "io.github.cosmicsilence.scalafix")
    scalafix {
        semanticdb.autoConfigure.set(true)
        semanticdb.version.set("4.9.0")
    }

    idea {

        module {

            excludeDirs = excludeDirs + files(

                "target",
                "out",

                ".idea",
                ".vscode",
                ".bloop",
                ".bsp",
                ".metals",
                "bin",

                ".ammonite",

                "logs",

                )

            isDownloadJavadoc = true
            isDownloadSources = true
        }
    }
}

subprojects {

    // https://stackoverflow.com/a/66352905/1772342

//    val signingKeyID = providers.gradleProperty("signing.gnupg.keyID")
    val signingSecretKey = providers.gradleProperty("signing.gnupg.secretKey")
    val signingKeyPassphrase = providers.gradleProperty("signing.gnupg.passphrase")
    signing {
        useGpgCmd()
        if (signingSecretKey.isPresent) {
            useInMemoryPgpKeys(signingSecretKey.get(), signingKeyPassphrase.get())
//            useInMemoryPgpKeys(signingKeyID.get(), signingSecretKey.get(), signingKeyPassphrase.get())
            sign(extensions.getByType<PublishingExtension>().publications)
        } else {
            logger.warn("PGP signing key not defined, skipping signing configuration")
        }
    }

    publishing {
        val suffix = "_" + vs.scala.v

        val rootID = vs.projectRootID

        val moduleID =
            if (project.name.equals(rootID))// rootID + "-" + "parent" + suffix
                throw kotlin.UnsupportedOperationException("root project should not be published")
            else if (project.name.equals("core")) rootID + suffix
            else rootID + "-" + project.name + suffix

        val whitelist = setOf("core")

        if (whitelist.contains(project.name)) {

            publications {
                create<MavenPublication>("maven") {

                    val javaComponent = components["java"] as AdhocComponentWithVariants
                    from(javaComponent)

                    javaComponent.withVariantsFromConfiguration(configurations["testFixturesApiElements"]) { skip() }
                    javaComponent.withVariantsFromConfiguration(configurations["testFixturesRuntimeElements"]) { skip() }

                    artifactId = moduleID
                    version = project.version.toString()

                    pom {
                        licenses {
                            license {
                                name.set("MIT")
                                url.set("http://opensource.org/licenses/MIT")
                            }
                        }

                        name.set("splain")
                        description.set("A scala compiler plugin for more concise errors")

                        val github = "https://github.com/tek"
                        val repo = github + "/splain"

                        url.set(repo)

                        developers {
                            developer {
                                id.set("tryp")
                                name.set("Torsten Schmits")
                                email.set("torstenschmits@gmail.com")
                                url.set(github)
                            }
                        }
                        scm {
                            connection.set("scm:git@github.com:tek/splain")
                            url.set(repo)
                        }
                    }
                }
            }
        }
    }
}

idea {

    targetVersion = "2020"

    module {

        excludeDirs = excludeDirs + files(
            ".gradle",
            "gradle",
            "spike",
            ".history"
        )
    }
}

================================================
FILE: buildSrc/build.gradle.kts
================================================
plugins {
    `kotlin-dsl`
}

repositories {
    mavenLocal()
    mavenCentral()
//    jcenter()
    maven("https://dl.bintray.com/kotlin/kotlin-dev")
}


================================================
FILE: buildSrc/src/main/kotlin/Versions.kt
================================================
import org.gradle.api.Project

class Versions(private val project: Project) {

    // TODO : how to group them?
    val projectGroup = "io.tryp"
    val projectRootID = "splain"

    val projectVMajor = "1.2.0"
    val projectV = projectVMajor + "-SNAPSHOT"

    inner class Scala {
        val group: String = project.properties["scalaGroup"]?.toString() ?: "org.scala-lang"

        val v: String = project.properties["scalaVersion"].toString()
        protected val vParts: List<String> = v.split('.').also { parts ->
            require(parts.size == 3) { "Scala version must be in format 'X.Y.Z' but was: $v" }
        }

        val majorV: String = vParts[0]
        val binaryV: String = vParts.subList(0, 2).joinToString(".")
        val patchV: String = vParts[2]

        val artifactSuffix = run {
            if (majorV == "3") majorV
            else binaryV
        }

        val jsV: String? = project.properties.get("scalaJSVersion")?.toString()
    }

    val scala: Scala by lazy { Scala() }
}


================================================
FILE: buildSrc/src/main/kotlin/init.kt
================================================
import org.gradle.api.Project

/**
 * Configures the current project as a Kotlin project by adding the Kotlin `stdlib` as a dependency.
 */
fun Project.versions(): Versions {

    return Versions(this)
}


================================================
FILE: core/build.gradle.kts
================================================
val vs: Versions = versions()

dependencies {

    // see https://github.com/gradle/gradle/issues/13067
    fun bothImpl(constraintNotation: Any) {
        implementation(constraintNotation)
        testFixturesImplementation(constraintNotation)
    }

    bothImpl("${vs.scala.group}:scala-compiler:${vs.scala.v}")

    testFixturesApi("com.chuusai:shapeless_${vs.scala.binaryV}:2.3.7")

    testFixturesApi("dev.zio:zio_${vs.scala.binaryV}:1.0.18")

    testFixturesApi("org.slf4j:slf4j-api:2.0.9")
    testRuntimeOnly("org.slf4j:slf4j-simple:2.0.9")
}

================================================
FILE: core/src/main/resources/scalac-plugin.xml
================================================
<plugin>
    <name>splain</name>
    <classname>splain.SplainPlugin</classname>
</plugin>


================================================
FILE: core/src/main/scala/splain/Messages.scala
================================================
package splain

object Messages {
  val hasMatching = "hasMatchingSymbol reported error: "

  val typingTypeApply = "typing TypeApply reported errors for the implicit tree: "

  val lazyDeriv = "could not find Lazy implicit"

  val WARNING = "[WARNING] "
}


================================================
FILE: core/src/main/scala/splain/PluginSettings.scala
================================================
package splain

import splain.PluginSettings.Keys.Key

import scala.collection.mutable
import scala.reflect.NameTransformer
import scala.util.{Failure, Success}

case class PluginSettings(pluginOpts: mutable.Map[String, String]) {}

object PluginSettings {

  case class IntKey(initV: Int) extends Keys.Key[Int] {
    override def parse(s: String): Int = s.toInt
  }

  case class BooleanKey(initV: Boolean) extends Key[Boolean] {
    override def parse(s: String): Boolean = s.toBoolean
  }

  case class StringKey(initV: String) extends Key[String] {
    override def parse(s: String): String = s
  }

  object Keys extends Enumeration {

    trait Key[T] extends Val with Product {

      def initV: T

      def parse(s: String): T

      def name: String = NameTransformer.decode(toString)
    }

    val enabled: BooleanKey = BooleanKey(true)

    val debug: BooleanKey = BooleanKey(false)

    val `Vimplicits-diverging`: BooleanKey = BooleanKey(false)

    val `Vimplicits-diverging-max-depth`: IntKey = IntKey(100)

    val `Vtype-detail`: StringKey = StringKey("1")

    val `Vtype-diffs-detail`: StringKey = StringKey("1")
  }

  lazy val nameToKey: List[(String, Key[_])] = {
    val vs = Keys.values.toList
      .collect { case v: Keys.Key[_] => v }

    vs.map { v =>
      v.name -> v
    }

  }

  lazy val nameToInitValue: List[(String, String)] = nameToKey.map { case (k, v) => k -> v.initV.toString }

  object TypeDetail extends Enumeration {

    val long: Value = Value(2)
    val existential: Value = Value(3)
    val reduction: Value = Value(4)
    val position: Value = Value(5)
    val alias: Value = Value(6)
  }

  object TypeDiffsDetail extends Enumeration {

    val disambiguation: Value = Value(2)
    val `builtin-msg`: Value = Value(3)
    val `builtin-msg-always`: Value = Value(4)
  }

  trait Implicits {

    def pluginSettings: PluginSettings

    implicit class KeyOps[T](self: Key[T]) {

      def get: T = {

        val key = self.name
        pluginSettings.pluginOpts
          .get(key)
          .map(self.parse)
          .getOrElse(
            throw new UnsupportedOperationException(s"$key is not defined")
          )
      }
    }

    implicit class BooleanKeyOps(self: BooleanKey) {

      def isEnabled: Boolean = {
        Keys.enabled.get && self.get
      }
    }

    case class DetailParsing[T <: Enumeration](key: StringKey, valueEnum: T) {

      lazy val raw: Seq[String] = key.get
        .split(',')
        .toList
        .map(_.trim)
        .filter { s =>
          s.nonEmpty
        }

      lazy val (number: Int, refined: Seq[valueEnum.Value]) = {

        val classified = raw.map { s =>
          scala.util.Try(s.toInt) match {
            case Failure(_) => Left(s)
            case Success(v) => Right(v)
          }
        }

        val refined: Seq[valueEnum.Value] = classified collect {
          case Left(v) =>
            valueEnum.withName(v)
        }
        val numbers: Seq[Int] = classified collect { case Right(v) => v }

        require(numbers.size <= 1, "only one numeric value is allowed")

        numbers.headOption.getOrElse(1) -> refined
      }

      trait ValueOps {

        val self: valueEnum.Value

        def isEnabled: Boolean = {

          Keys.enabled.get &&
          (number >= self.id || refined.contains(self))
        }
      }
    }

    val typeDetailParsing: DetailParsing[TypeDetail.type] =
      DetailParsing(Keys.`Vtype-detail`, TypeDetail)
    implicit class TypeDetailValueOps(val self: TypeDetail.Value) extends typeDetailParsing.ValueOps {}

    val typeDiffsDetailParsing: DetailParsing[TypeDiffsDetail.type] =
      DetailParsing(Keys.`Vtype-diffs-detail`, TypeDiffsDetail)
    implicit class TypeDiffsDetailValueOps(val self: TypeDiffsDetail.Value) extends typeDiffsDetailParsing.ValueOps {}

  }
}


================================================
FILE: core/src/main/scala/splain/SplainInternalError.scala
================================================
package splain

class SplainInternalError(detail: String, cause: Throwable = null)
    extends InternalError(
      "You've found a bug in splain formatting extension," +
        " please post this error with stack trace on https://github.com/tek/splain/issues\n\n" +
        detail,
      cause
    ) {}


================================================
FILE: core/src/main/scala/splain/format/package.scala
================================================
package splain

package object format {

  // TODO: this entire package could be gone, already taken over by scalac formatting
}


================================================
FILE: core/src/main/scala/splain/test/AutoLift.scala
================================================
package splain.test

import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}
import java.util.Base64
import scala.reflect.macros.blackbox

trait AutoLift {

  type Bound

  def asCode(value: Bound): String

  trait Mixin {

    val c: blackbox.Context
    import c.universe._

    implicit def _liftable[T <: Bound]: Liftable[T] = Liftable.apply { value: T =>
      val code = asCode(value)

      val parsed = c.parse(code)
      parsed
    }
  }
}

object AutoLift {

  val MAX_LITERAL_LENGTH = 32768

  object SerializingLift extends AutoLift {

    type Bound = Serializable

    lazy val encoder: Base64.Encoder = Base64.getEncoder
    lazy val decoder: Base64.Decoder = Base64.getDecoder

    lazy val fullPath: String = this.getClass.getCanonicalName.stripSuffix("$")

    override def asCode(value: Bound): String = {

      val bOStream = new ByteArrayOutputStream()
      val oOStream = new ObjectOutputStream(bOStream)

      oOStream.writeObject(value)

      val serialized = encoder.encodeToString(bOStream.toByteArray)

      val chunks = serialized.sliding(MAX_LITERAL_LENGTH, MAX_LITERAL_LENGTH).toList

      val chunkExpr = chunks
        .map { cc =>
          s"\"$cc\""
        }
        .mkString("(", ", ", ")")

      val typeStr = {
        val canonicalName = value.getClass.getCanonicalName
        if (canonicalName.endsWith("$"))
          canonicalName.stripSuffix("$") + ".type"
        else canonicalName
      }

      val result = s"""
         |$fullPath.fromPreviousStage[$typeStr]$chunkExpr
         |""".stripMargin

      result
    }

    def fromPreviousStage[T <: Serializable](strs: String*): T = {

      val bytes = strs
        .map { str =>
          decoder.decode(str)
        }
        .reduce(_ ++ _)

      val bIStream = new ByteArrayInputStream(bytes)
      val oIStream = new ObjectInputStream(bIStream)

      val v = oIStream.readObject()
      v.asInstanceOf[T]
    }
  }
}


================================================
FILE: core/src/main/scala/splain/test/CachingFrontEnd.scala
================================================
package splain.test

import scala.collection.mutable.ArrayBuffer
import scala.tools.reflect.FrontEnd

// mimic of StoreReporter
case class CachingFrontEnd(sourceName: String) extends FrontEnd {

  val cached: ArrayBuffer[Issue] = ArrayBuffer.empty[Issue]

  override def display(info: Info): Unit = {

    val issue = Issue(
      info.severity.id,
      info.msg,
      info.pos,
      sourceName
    )

    this.cached += issue
  }

  override def reset(): Unit = {
    super.reset()
    cached.clear()
  }
}

object CachingFrontEnd {

  object NoSource extends CachingFrontEnd("")
}


================================================
FILE: core/src/main/scala/splain/test/Issue.scala
================================================
package splain.test

import scala.collection.immutable.ArraySeq
import scala.reflect.internal.util.{BatchSourceFile, NoPosition, Position}
import scala.util.Try

@SerialVersionUID(5124466488126506935L)
case class Issue(
    severity: Int,
    msg: String,
    @transient pos: Position,
    sourceName: String = Issue.defaultSrcName,
    isShortName: Boolean = false
) extends Serializable {

  // mimic of PrintReporter.display
  val display: String = {

    lazy val severityDisplay: String = new CachingFrontEnd.NoSource.Severity(severity).toString.toLowerCase

    val posWithFileName = Try(
      pos.withSource(
        new BatchSourceFile(sourceName, ArraySeq.unsafeWrapArray(pos.source.content))
      )
    )

    val infoStr = s"$severityDisplay: $msg"

    val result = posWithFileName
      .map { pos =>
        val formatted = Position.formatMessage(pos, infoStr, shortenFile = true)
        formatted
      }
      .recover {
        case ee: Exception =>
          val formatted = Position.formatMessage(
            NoPosition,
            s"""$infoStr
               |with error: $ee
               |""".stripMargin,
            shortenFile = true
          )
          formatted

      }
      .get

    result
  }

  override def toString: String = {

    display
  }
}

object Issue {

  lazy val defaultSrcName: "newSource1.scala" = "newSource1.scala"
}


================================================
FILE: core/src/main/scala/splain/test/TryCompile.scala
================================================
package splain.test

import scala.language.experimental.macros
import scala.language.implicitConversions
import scala.reflect.runtime.{currentMirror, universe}
import scala.tools.nsc.reporters.{Reporter, StoreReporter}
import scala.tools.nsc.{Global, Settings}
import scala.tools.reflect.ToolBox

trait TryCompile extends Product with Serializable {

  def issues: Seq[Issue]

  case class Level(level: Int) {

    def filteredIssues: Seq[Issue] = issues.filter { i =>
      i.severity == level
    }

    def displayIssues: String = issues
      .map { i =>
        i.display
      }
      .mkString("\n")
  }

  object Error extends Level(2)
  object Warning extends Level(1)
  object Info extends Level(0)

  override lazy val toString: String = {
    s"""
       |$productPrefix
       | ---
       |${issues.mkString("\n\n")}
       |""".stripMargin
  }
}

object TryCompile {

  trait Resolved extends TryCompile

  case class Success(
      issues: Seq[Issue] = Nil
  ) extends Resolved {

    abstract class Evaluable extends Success(issues) {

      def get: Any
    }
  }

  object Empty extends Success()

  trait Failure extends Resolved

  case class TypingError(issues: Seq[Issue] = Nil) extends Failure
  case class ParsingError(issues: Seq[Issue] = Nil) extends Failure
  case class OtherFailure(e: Throwable) extends Failure {
    override def issues: Seq[Issue] = Nil
  }

  trait Engine {

    def args: String

    final def apply(code: String): TryCompile =
      try {
        doCompile(code)
      } catch {
        case e: Throwable =>
          OtherFailure(e)
      }

    def doCompile(code: String): TryCompile
  }

  val mirror: universe.Mirror = currentMirror

  case class UseReflect(args: String, sourceName: String = Issue.defaultSrcName) extends Engine {

    override def doCompile(code: String): TryCompile = {

      val frontEnd = CachingFrontEnd(sourceName)

      val toolBox: ToolBox[universe.type] = mirror.mkToolBox(frontEnd, options = args)

      def cached: Seq[Issue] = frontEnd.cached.toSeq

      val parsed =
        try {
          toolBox.parse(code.trim)
        } catch {
          case _: Throwable =>
            return TryCompile.ParsingError(cached)
        }

      val compiled =
        try {
//        toolBox.typecheck(parsed, withImplicitViewsDisabled = false)
          toolBox.compile(parsed)
        } catch {
          case _: Throwable =>
            return TryCompile.TypingError(cached)
        }

      val success = Success(cached)
      new success.Evaluable {
        override def get: Any = compiled()
      }

    }
  }

  case class UseNSC(args: String, sourceName: String = Issue.defaultSrcName) extends Engine {

    val global: Global = {
      val _settings = new Settings()

      _settings.reporter.value = classOf[StoreReporter].getCanonicalName
      _settings.usejavacp.value = true
      _settings.processArgumentString(args)

      val global: Global = Global(_settings, Reporter(_settings))
      global
    }

    val reporter: StoreReporter = global.reporter.asInstanceOf[StoreReporter]

    override def doCompile(code: String): TryCompile = reporter.synchronized { // shared reporter is not thread safe

      reporter.reset()

      val tree = global.newCompilationUnit(code.trim, sourceName)

      val run = new global.Run()

      val parser = global.newUnitParser(tree)
      parser.parse()

      def reports = reporter.infos.toSeq.map { info =>
        Issue(info.severity.id, info.msg, info.pos, sourceName)
      }

      val result = if (reports.exists(v => v.severity == Empty.Error.level)) {

        ParsingError(reports)
      } else {

        run.compileUnits(List(tree))

        val success = Success(reports)
        if (success.Error.filteredIssues.nonEmpty) {
          TypingError(reports)
        } else {
          success
        }
      }

      result
    }
  }

  case class Static[N <: String with Singleton](sourceName: N) {

    type NN = N

    def apply(code: String): TryCompile = macro TryCompileMacros.compileCodeTree[N]

    trait FromCodeMixin {

      implicit def code2TryCompile(code: String): TryCompile = macro TryCompileMacros.compileCodeTree[N]
    }
  }

  object Static {

    val default: Static["newSource1.scala"] = Static(Issue.defaultSrcName)

    def apply(): Static["newSource1.scala"] = default
  }
}


================================================
FILE: core/src/main/scala/splain/test/TryCompileMacros.scala
================================================
package splain.test

import splain.test.AutoLift.SerializingLift

import scala.collection.mutable.ArrayBuffer
import scala.reflect.macros.{whitebox, ParseException, TypecheckException}
import scala.tools.nsc.Global
import scala.tools.nsc.reporters.FilteringReporter

class TryCompileMacros(val c: whitebox.Context) extends SerializingLift.Mixin {
  import c.universe._

  lazy val global: Global = c.universe.asInstanceOf[Global]

  def reporter: FilteringReporter = global.reporter

  lazy val defaultSrcLit: Literal = Literal(Constant(Issue.defaultSrcName))

  type CodeTree = Tree

  // TODO: from shapeless.test.IllTypedMacros, no idea what it is for
  def rectifyCode(codeStr: String): String = {

    val dummy0 = TermName(c.freshName())
    val dummy1 = TermName(c.freshName())
    s"object $dummy0 { val $dummy1 = { $codeStr } }"
  }

  final def tree2Str(code: CodeTree): String = {

    code match {
      case Literal(v) =>
        v.value.asInstanceOf[String]
      case _ =>
        throw new UnsupportedOperationException(
          s"`$code` (${code.getClass.getName}) is not a Literal, please only use Literal or final val with refined or no type annotation"
        )
    }
  }

  final def type2Str(tt: Type): String = {

    tt.dealias match {
      case v: ConstantType => v.value.value.asInstanceOf[String]
      case _ =>
        throw new UnsupportedOperationException(
          s"cannot parse type $tt : ${tt.getClass}"
        )
    }
  }

  def compileCodeTree[N <: String with Singleton: c.WeakTypeTag](code: CodeTree): Tree = {

    val _code = tree2Str(code).trim

    val _name = type2Str(implicitly[c.WeakTypeTag[N]].tpe)

    val result = run(_code, _name)

    result
  }

  def run(codeStr: String, sourceName: String): Tree = {

    val cached = ArrayBuffer.empty[Issue]

    val parsed =
      try {
        c.parse(codeStr)
      } catch {
        case e: ParseException =>
          cached += Issue(
            TryCompile.Empty.Error.level,
            e.msg,
            e.pos.asInstanceOf[scala.reflect.internal.util.Position],
            sourceName
          )

          val result = TryCompile.ParsingError(cached.toSeq)

          return q"$result"
      }

    val compiled: c.Tree =
      try {
        c.typecheck(parsed)
      } catch {
        case e: TypecheckException =>
          cached += Issue(
            TryCompile.Empty.Error.level,
            e.msg,
            e.pos.asInstanceOf[scala.reflect.internal.util.Position],
            sourceName
          )
          // TODO: this can only capture the first error, which makes the result different from runtime compilation
          //   unfortunately there is nothing we can do

          val result = TryCompile.TypingError(cached.toSeq)

          return q"$result"
      }

    val success = TryCompile.Success(cached.toSeq)

//    q"$success"

    q"""
      val ss = $success

      new ss.Evaluable {
        override def get: Any = {
          $compiled
        }
      }
     """
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/ImplicitsExtension.scala
================================================
package splain

import scala.collection.concurrent.TrieMap
import scala.collection.mutable
import scala.tools.nsc.typechecker

trait ImplicitsExtension extends TyperCompatViews with typechecker.Implicits {
  self: SplainAnalyzer =>

  import global._

  object ImplicitsHistory {

    lazy val currentGlobal: Global = {
      val result = Global()
      result
    }

    case class Global() {

      val localByPosition: TrieMap[PositionIndex, Local] = TrieMap.empty
    }

    case class Local() {

      object DivergingImplicitErrors {

        val errors: mutable.ArrayBuffer[DivergentImplicitTypeError] = mutable.ArrayBuffer.empty

        def push(v: DivergentImplicitTypeError): Unit = {
          errors.addOne(v)
        }

        val linkedErrors = mutable.HashSet.empty[DivergentImplicitTypeError]

        def getUnlinkedMsgs: Seq[String] = {

          val Seq(msgs, linkedMsgs) = Seq(errors.toSeq, linkedErrors.toSeq).map { seq =>
            seq.map(v => DivergingImplicitErrorView(v).errMsg).distinct
          }

          val linkedMsgSet = linkedMsgs.toSet

          val result = msgs.filterNot { str =>
            linkedMsgSet.contains(str)
          }

          result
        }

        val logs: mutable.ArrayBuffer[String] = mutable.ArrayBuffer.empty[String]
        // unused messages & comments will be displayed at the end of the implicit error
      }
    }
  }

  override def inferImplicit(
      tree: Tree,
      pt: Type,
      reportAmbiguous: Boolean,
      isView: Boolean,
      context: Context,
      saveAmbiguousDivergent: Boolean,
      pos: Position
  ): SearchResult = {

    import ImplicitsHistory._
    import PluginSettings.Keys._

    def getResult = super.inferImplicit(tree, pt, reportAmbiguous, isView, context, saveAmbiguousDivergent, pos)

    if (settings.Vimplicits.value && `Vimplicits-diverging`.isEnabled) {

      val posII = PositionIndex(
        tree.pos
      )

      val local = currentGlobal.localByPosition.getOrElseUpdate(posII, Local())
      val previousSimilarErrors = local.DivergingImplicitErrors.errors.filter { ee =>
        ee.underlyingTree equalsStructure tree
      }

      val previousSimilarErrorsN = previousSimilarErrors.size
      if (previousSimilarErrorsN >= `Vimplicits-diverging-max-depth`.get) {

        local.DivergingImplicitErrors.logs +=
          s"""
             |Implicit search for $tree
             |has reported $previousSimilarErrorsN diverging errors
             |Terminated
             |    at ${pos.showDebug}
             |""".stripMargin.trim

//        s"Terminating implicit search for $tree at ${pos.showDebug} " +
//          s"after reporting ${settingVImplicitDivergingThreshold} Diverging implicit errors"
        return SearchFailure
      }

      val result = getResult

      val divergingErrors = context.reporter.errors.collect {
        case ee: DivergentImplicitTypeError =>
          ee
      }

      divergingErrors.foreach { ee =>
        local.DivergingImplicitErrors.push(ee)

//        require(ee.pt0 == pt, s"mismatch! ${ee.pt0} != $pt")

        context.reporter.retainDivergentErrorsExcept(ee)
      }

//      val cc = result.isSuccess || result == SearchFailure

      result
    } else {

      val result: SearchResult = getResult
      result
    }
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/SplainAnalyzer.scala
================================================
package splain

import scala.collection.mutable
import scala.tools.nsc._

class SplainAnalyzer(val global: Global, val pluginSettings: PluginSettings)
    extends typechecker.Analyzer
    with SplainFormattingExtension
    with ImplicitsExtension
    with SplainAnalyzerShim
    with PluginSettings.Implicits {

  override val specialFormatters: List[SpecialFormatter] =
    List(
      FunctionFormatter,
      TupleFormatter,
      ShapelessRecordItemFormatter,
      RefinedFormatterImproved,
//      RefinedFormatter,
      ByNameFormatter
    )

  override def splainFoundReqMsg(found: global.Type, req: global.Type): String = {
    val original = super.splainFoundReqMsg(found, req)

    val extra = mutable.Buffer.empty[String]

    if (PluginSettings.Keys.debug.isEnabled) {

      extra += "===[ ORIGINAL ERROR ]===" +
        builtinFoundReqMsg(found, req) +
        "\n"
    }

    val result = (Seq(original) ++ extra.toSeq).mkString("\n")
    result
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/SplainAnalyzerShim.scala
================================================
package splain

import scala.tools.nsc.typechecker.Analyzer

trait SplainAnalyzerShim {
  self: SplainAnalyzer =>

  def migrateFrom(old: Analyzer): Unit = {

    // fix for #81: transfer deferredOpen that are cached before this initializer
    old.packageObjects.deferredOpen.foreach { v =>
      self.packageObjects.deferredOpen.add(v.asInstanceOf[self.global.Symbol])
    }
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/SplainFormattersExtension.scala
================================================
package splain

import scala.tools.nsc.typechecker.splain._

object SplainFormattersExtension {}

trait SplainFormattersExtension extends SplainFormatters {
  self: SplainAnalyzer =>

  import global._

  object RefinedFormatterImproved extends SpecialFormatter {

    object DeclSymbol {
      def unapply(sym: Symbol): Option[(Formatted, Formatted)] =
        if (sym.hasRawInfo)
          Some((Simple(sym.simpleName.toString), formatType(sym.rawInfo, top = true)))
        else
          None
    }

    val ignoredTypes: List[Type] = List(typeOf[Object], typeOf[Any], typeOf[AnyRef])

    def sanitizeParents: List[Type] => List[Type] = { ps =>
      val tpes = ps.distinct
      val result = tpes.filterNot(t => ignoredTypes.exists(_ =:= t))

      if (result.isEmpty) tpes.headOption.toList
      else result
    }

    object Refined {
      def unapply(tpe: Type): Option[(List[Type], Scope)] =
        tpe match {
          case TypeRef(pre, sym, List(RefinedType(parents, decls)))
              if decls.isEmpty && pre.typeSymbol.fullName == "zio" && sym.fullName == "zio.Has" =>
            val sanitized = sanitizeParents(parents)
            if (sanitized.length == 1)
              Some((List(TypeRef(pre, sym, sanitized.headOption.toList)), decls))
            else
              None
          case RefinedType(types, scope) =>
            if (scope.isEmpty) {
              val subtypes = types.map(v => dealias(v)).flatMap {
                case Refined(types, _) =>
                  types
                case tpe =>
                  List(tpe)
              }
              Some((subtypes, scope))
            } else
              Some((types, scope))
          case t @ SingleType(_, _) =>
            unapply(t.underlying)
          case _ =>
            None
        }
    }

    def formatDecl: Symbol => Formatted = {
      case sym if sym.hasRawInfo && sym.rawInfo.isInstanceOf[TypeBounds] =>
        val name = sym.simpleName.toString
        val bounds = formatType(sym.rawInfo, top = true)
        val boundsStr = self.showFormatted(bounds)
        Simple(s"type $name$boundsStr")
      case DeclSymbol(n, t) =>
        Decl(n, t)
      case sym =>
        Simple(sym.toString)
    }

    val none: Formatted = Simple("<none>")

    def separate[A](left: List[A], right: List[A]): (List[A], List[A], List[A]) = {
      val leftS = Set(left: _*)
      val rightS = Set(right: _*)
      val common = leftS.intersect(rightS)
      val uniqueLeft = leftS -- common
      val uniqueRight = rightS -- common
      (common.toList, uniqueLeft.toList, uniqueRight.toList)
    }

    def compareTypes(left: List[Type], right: List[Type]): List[Formatted] = {
      val (common, uniqueLeft, uniqueRight) =
        separate(left.map(formatType(_, top = true)), right.map(formatType(_, top = true)))
      val diffs = uniqueLeft
        .zipAll(uniqueRight, none, none)
        .map {
          case (l, r) =>
            Diff(l, r)
        }
      common ++ diffs
    }

    def filterDecls(syms: List[Symbol]): List[(Formatted, Formatted)] =
      syms.collect {
        case DeclSymbol(sym, rhs) =>
          (sym, rhs)
      }

    def compareDecls(left: List[Symbol], right: List[Symbol]): List[Formatted] = {
      val (common, uniqueLeft, uniqueRight) = separate(filterDecls(left), filterDecls(right))
      val diffs = uniqueLeft
        .map(Some(_))
        .zipAll(uniqueRight.map(Some(_)), None, None)
        .collect {
          case (Some((sym, l)), Some((_, r))) =>
            DeclDiff(sym, l, r)
          case (None, Some((sym, r))) =>
            DeclDiff(sym, none, r)
          case (Some((sym, l)), None) =>
            DeclDiff(sym, l, none)
        }
      common.map {
        case (sym, rhs) =>
          Decl(sym, rhs)
      } ++ diffs
    }

    override def apply[A](
        tpe: Type,
        simple: String,
        args: List[A],
        formattedArgs: => List[Formatted],
        top: Boolean
    )(rec: (A, Boolean) => Formatted): Option[Formatted] = {
      tpe match {
        case Refined(parents, decls) =>
          def elements = sanitizeParents(parents).map(formatType(_, top))

          val result = Some(RefinedForm(elements, decls.toList.map(formatDecl)))
          result
        case _ =>
          None
      }
    }

    override def diff(left: Type, right: Type, top: Boolean): Option[Formatted] =
      (left, right) match {
        case (Refined(leftParents, leftDecls), Refined(rightParents, rightDecls)) =>
          val parents = compareTypes(sanitizeParents(leftParents), sanitizeParents(rightParents)).sorted
          val decls = compareDecls(leftDecls.toList, rightDecls.toList).sorted
          val result = Some(RefinedForm(parents, decls))
          result
        case _ =>
          None
      }
  }

  object ShapelessRecordItemFormatter extends SpecialFormatter {
    def keyTagName = "shapeless.labelled.KeyTag"

    def taggedName = "shapeless.tag.Tagged"

    def isKeyTag(tpe: Type): Boolean = tpe.typeSymbol.fullName == keyTagName

    def isTagged(tpe: Type): Boolean = tpe.typeSymbol.fullName == taggedName

    object extractRecord {
      def unapply(tpe: Type): Option[(global.Type, global.Type)] =
        tpe match {
          case RefinedType(actual :: key :: Nil, _) if isKeyTag(key) =>
            Some((actual, key))
          case _ =>
            None
        }
    }

    object extractStringConstant {
      def unapply(tpe: Type): Option[String] =
        tpe match {
          case ConstantType(Constant(a: String)) =>
            Some(a)
          case _ =>
            None
        }
    }

    def formatConstant(tag: String): PartialFunction[Type, String] = {
      case a if a == typeOf[scala.Symbol] =>
        s"'$tag"
    }

    def formatKeyArg: PartialFunction[List[Type], Option[Formatted]] = {
      case RefinedType(parents, _) :: _ :: Nil =>
        for {
          main <- parents.headOption
          tagged <- parents.find(isTagged)
          headArg <- tagged.typeArgs.headOption
          tag <- extractStringConstant.unapply(headArg)
          repr <- formatConstant(tag).lift(main)
        } yield Simple(repr)
      case extractStringConstant(tag) :: _ :: Nil =>
        Some(Simple(s""""$tag""""))
      case tag :: _ :: Nil =>
        Some(formatType(tag, top = true))
    }

    def formatKey(tpe: Type): Formatted = formatKeyArg.lift(tpe.typeArgs).flatten.getOrElse(formatType(tpe, top = true))

    def recordItem(actual: Type, key: Type): Infix =
      Infix(Simple("->>"), formatKey(key), formatType(actual, top = true), top = false)

    def diff(left: Type, right: Type, top: Boolean): Option[Formatted] =
      left -> right match {
        case (extractRecord(a1, k1), extractRecord(a2, k2)) =>
          val rec: ((Formatted, Formatted), Boolean) => Formatted = {
            case ((l, r), _) =>
              if (l == r)
                l
              else
                Diff(l, r)
          }
          val left = formatKey(k1) -> formatKey(k2)
          val right = formatType(a1, top = true) -> formatType(a2, top = true)
          Some(formatInfix(Nil, "->>", left, right, top)(rec))
        case _ =>
          None
      }

    override def apply[A](
        tpe: Type,
        simple: String,
        args: List[A],
        formattedArgs: => List[Formatted],
        top: Boolean
    )(rec: (A, Boolean) => Formatted): Option[Formatted] = {
      tpe match {
        case extractRecord(actual, key) =>
          Some(recordItem(actual, key))
        case _ =>
          None
      }
    }
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/SplainFormattingExtension.scala
================================================
package splain

import scala.annotation.tailrec
import scala.collection.concurrent.TrieMap
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.tools.nsc.typechecker
import scala.tools.nsc.typechecker.splain._

object SplainFormattingExtension {

  import scala.reflect.internal.TypeDebugging.AnsiColor._

  val ELLIPSIS: String = "⋮".blue

  val | = "┃"
  val vertical_| = "━━━━━━━━:"
}

trait SplainFormattingExtension extends typechecker.splain.SplainFormatting with SplainFormattersExtension {
  self: SplainAnalyzer =>

  import SplainFormattingExtension._
  import global._
  import PluginSettings._

  case class SplainImplicitErrorLink(
      fromTree: ImplicitError,
      fromHistory: DivergentImplicitTypeError
  ) {

    val sameCandidateTree: Boolean = fromTree.candidate equalsStructure fromHistory.underlyingTree

    val samePendingType: Boolean = fromTree.specifics match {
      case ss: ImplicitErrorSpecifics.NotFound =>
        fromHistory.pt0 =:= ss.param.tpe
      case _ =>
        false
    }

    val moreSpecificPendingType: Boolean = fromTree.specifics match {
      case ss: ImplicitErrorSpecifics.NotFound =>
        fromHistory.pt0 <:< ss.param.tpe
      case _ =>
        false
    }

    val sameStartingWith: Boolean = {
      fromHistory.sym.fullLocationString == fromTree.candidate.symbol.fullLocationString
    }

    //    lazy val divergingSearchStartingWithHere: Boolean = sameStartingWith

    lazy val divergingSearchDiscoveredHere: Boolean = sameCandidateTree && moreSpecificPendingType
  }

  case class SplainImplicitErrorTree(
      error: ImplicitError,
      children: Seq[SplainImplicitErrorTree] = Nil
  ) {

    import SplainImplicitErrorTree._

    def doCollectFull(alwaysDisplayRoot: Boolean = false): Seq[NodeForShow] = {

      if (children.isEmpty) Seq(NodeForShow(error, alwaysShow = true))
      else {

        Seq(NodeForShow(error, alwaysShow = alwaysDisplayRoot)) ++ {

          if (children.size >= 2) children.flatMap(_.doCollectFull(true))
          else children.flatMap(_.doCollectFull())
        }
      }
    }

    lazy val collectFull: Seq[NodeForShow] = doCollectFull(true)

    lazy val collectCompact: Seq[NodeForShow] = {

      val displayed = collectFull.zipWithIndex.filter {
        case (v, _) =>
          v.alwaysShow
      }

      val ellipsisIndices = displayed.map(_._2 - 1).toSet + (collectFull.size - 1)

      val withEllipsis = displayed.map {
        case (v, i) =>
          if (!ellipsisIndices.contains(i)) v.copy(showEllipsis = true)
          else v
      }

      withEllipsis
    }

    case class FormattedChain(
        source: Seq[NodeForShow]
    ) {

      val toList: List[String] = {
        val collected = source.toList
        val baseIndent = collected.headOption.map(_.nesting).getOrElse(0)

        val formatted = collected.map { v =>
          val formatted = v.formatted
          if (v.showEllipsis) formatted.copy(_2 = formatted._2 :+ ELLIPSIS)
          else formatted
        }

        indentTree(formatted, baseIndent)
      }

      override lazy val toString: String = toList.mkString("\n")
    }

    object FormattedChain {

      object Full extends FormattedChain(collectFull)

      object Compact extends FormattedChain(collectCompact)

      lazy val VimplicitsVerboseTree: Boolean = settings.VimplicitsVerboseTree.value
      val display: FormattedChain = if (VimplicitsVerboseTree) Full else Compact
    }

    override def toString: String = FormattedChain.Full.toString
  }

  object SplainImplicitErrorTree {

    case class NodeForShow(
        error: ImplicitError,
        alwaysShow: Boolean,
        showEllipsis: Boolean = false
    ) {

      def nesting: RunId = error.nesting

      val formatted: (String, List[String], RunId) =
        formatNestedImplicit(error)
    }

    def fromError(
        error: ImplicitError,
        offsprings: List[ImplicitError]
    ): SplainImplicitErrorTree = {
      val topNesting = error.nesting

      val children = fromChildren(
        offsprings,
        topNesting
      )

      SplainImplicitErrorTree(error, children)
    }

    def fromChildren(
        offsprings: List[ImplicitError],
        topNesting: Int
    ): List[SplainImplicitErrorTree] = {

      if (offsprings.isEmpty)
        return Nil

      val minNesting = offsprings.map(v => v.nesting).min

      if (minNesting < topNesting + 1)
        throw new SplainInternalError(
          "Detail: nesting level of offsprings of an implicit search tree node should be higher"
        )

      val wII = offsprings.zipWithIndex

      val childrenII = wII
        .filter {
          case (sub, _) =>
            if (sub.nesting < minNesting) {
              throw new SplainInternalError(
                s"Detail: Sub-node in implicit tree can only have nesting level larger than top node," +
                  s" but (${sub.nesting} < $minNesting)"
              )
            }

            sub.nesting == minNesting
        }
        .map(_._2)

      val ranges = {

        val seqs = (childrenII ++ Seq(offsprings.size))
          .sliding(2)
          .toList

        seqs.map {
          case Seq(from, until) =>
            from -> until
          case _ =>
            throw new SplainInternalError("Detail: index should not be empty")
        }
      }

      val children = ranges.map { range =>
        val _top = offsprings(range._1)

        val _offsprings = offsprings.slice(range._1 + 1, range._2)

        fromError(
          _top,
          _offsprings
        )
      }

      mergeDuplicates(children)
      //      children
    }

    def mergeDuplicates(children: List[SplainImplicitErrorTree]): List[SplainImplicitErrorTree] = {
      val errors = children.map(_.error).distinct

      val grouped = errors.map { ee =>
        val group = children.filter(c => c.error == ee)

        val mostSpecificError = group.head.error
        // TODO: this old design is based on a huge hypothesis, should it be improved
        //        val mostSpecificError = group.map(_.error).maxBy(v => v.candidate.toString.length)

        val allChildren = group.flatMap(v => v.children)
        val mergedChildren = mergeDuplicates(allChildren)

        SplainImplicitErrorTree(mostSpecificError, mergedChildren)
      }

      grouped.distinctBy(v => v.FormattedChain.Full.toString) // TODO: this may lose information
    }
  }

  object ImplicitErrorExtension {

    def unapplyCandidate(e: ImplicitError): Tree = unapplyRecursively(e.candidate)

    @tailrec
    private def unapplyRecursively(tree: Tree): Tree =
      tree match {
        case TypeApply(fun, _) => unapplyRecursively(fun)
        case Apply(fun, _) => unapplyRecursively(fun)
        case a => a
      }

    def cleanCandidate(e: ImplicitError): String =
      unapplyCandidate(e).toString match {
        case ImplicitError.candidateRegex(suf) => suf
        case a => a
      }
  }

  override def formatNestedImplicit(err: ImplicitError): (String, List[String], Int) = {

    val base = super.formatNestedImplicit(err)

    import scala.reflect.internal.TypeDebugging.AnsiColor._
    val candidate = ImplicitErrorExtension.cleanCandidate(err)
    val problem = s"${candidate.red} invalid because"

    object ImplicitErrorsInHistory {

      lazy val posI: self.PositionIndex = PositionIndex(
        err.candidate.pos
      )

      lazy val localHistoryOpt: Option[ImplicitsHistory.Local] =
        ImplicitsHistory.currentGlobal.localByPosition.get(posI)

      lazy val diverging: Seq[DivergentImplicitTypeError] = {

        localHistoryOpt.toSeq.flatMap { history =>
          history.DivergingImplicitErrors.errors
        }
      }
    }

    val extra = mutable.Buffer.empty[String]

    extra ++= base._2

    val discoveredHere = ImplicitErrorsInHistory.diverging.find { inHistory =>
      val link = SplainImplicitErrorLink(err, inHistory)

      link.divergingSearchDiscoveredHere
    }

    discoveredHere match {
      case Some(ee) =>
        ImplicitErrorsInHistory.localHistoryOpt.foreach { history =>
          history.DivergingImplicitErrors.linkedErrors += ee
        }

        val text = DivergingImplicitErrorView(ee).errMsg

        extra ++= text.split('\n').filter(_.trim.nonEmpty)
      case _ =>
    }

    (problem, extra.toList, base._3)
  }

  override def formatWithInfix[A](tpe: Type, args: List[A], top: Boolean)(rec: (A, Boolean) => Formatted): Formatted = {
    val (path, simple) = formatSimpleType(tpe)
    tpe.nameAndArgsString
    lazy val formattedArgs = args.map(rec(_, true))
    val special = formatSpecial(tpe, simple, args, formattedArgs, top)(rec)
    special.getOrElse {
      args match {
        case left :: right :: Nil if isSymbolic(tpe) => formatInfix(path, simple, left, right, top)(rec)
        case _ :: _ => Applied(Qualified(path, SimpleName(simple)), formattedArgs)
        case _ => Qualified(path, SimpleName(simple))
      }
    }
  }

  override def formatImplicitError(
      param: Symbol,
      errors: List[ImplicitError],
      annotationMsg: String
  ): String = {

    val msg = implicitMessage(param, annotationMsg)
    val errorTrees = SplainImplicitErrorTree.fromChildren(errors, -1)

    val errorTreesStr = errorTrees.map(_.FormattedChain.display.toString)

    val addendum = errorTrees.headOption.toSeq.flatMap { head =>
      import ImplicitsHistory._

      val pos = head.error.candidate.pos
      val localHistoryOpt = currentGlobal.localByPosition.get(PositionIndex(pos))
      val addendum: Seq[String] = localHistoryOpt.toSeq.flatMap { history =>
        val unlinkedMsgs = history.DivergingImplicitErrors.getUnlinkedMsgs

        val unlinkedText = if (unlinkedMsgs.nonEmpty) {
          val indented = unlinkedMsgs.flatMap { str =>
            indentTree(List((str, Nil, 0)), 1)
          }

          Seq(
            Messages.WARNING + "The following reported error(s) cannot be linked to any part of the implicit search tree:"
          ) ++
            indented

        } else {
          Nil
        }

        val logs = history.DivergingImplicitErrors.logs

        val logsText = if (logs.nonEmpty) {

          val indented = logs.flatMap { str =>
            indentTree(List((str, Nil, 0)), 1)
          }

          Seq(Messages.WARNING + "Implicit search may be broken:") ++
            indented

        } else {
          Nil
        }

        val text = unlinkedText ++ logsText

        text
      }

      addendum
    }

    val components: Seq[String] =
      Seq("implicit error;") ++
        msg ++
        errorTreesStr ++
        addendum

    val result = components.mkString("\n")

    result
  }

  override def extractArgs(tpe: Type): List[global.Type] = TypeView(tpe).extractArgs

  override def stripType(tt: Type): (List[String], String) = {

    val view = TypeView(tt)
    view.path -> view.noArgShortName
  }

  // new implementation is idempotent and won't lose information
  override def dealias(tpe: Type): Type = {

    TypeView(tpe).dealias_normal
  }

  case class FormattedIndex(
      ft: Formatted,
      idHash: Int
  )

  object FormattedIndex {

    def apply(ft: Formatted) = new FormattedIndex(
      ft,
      System.identityHashCode(ft)
    )
  }

  trait Based {

    def element: Formatted

    protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr])

    lazy val flat: String = {
      val (header, body) = formattedHeader_Body(false)

      if (body.isEmpty) header
      else s"$header { ${body.map(v => v.flat).mkString(";")} }"
    }

    lazy val broken: Seq[String] = {
      val (header, body) = formattedHeader_Body(true)
      val result = indentTree(List((header, body.flatMap(_.lines).toList, 0)), 1)

      result
    }
  }

  object Based {

    lazy val lookup: TrieMap[FormattedIndex, ArrayBuffer[Based]] = TrieMap.empty

    // MultiMap shortcuts
    def +=(kv: (FormattedIndex, Based)): Unit = {

      lookup.getOrElseUpdate(kv._1, ArrayBuffer.empty) += kv._2
    }

    def getAll(k: FormattedIndex): List[Based] = lookup.get(k).toList.flatten
  }

  case class Reduction(
      element: Formatted,
      from: (String, Formatted)
  ) extends Based {

    def index(): Unit = {

      if (TypeDetail.reduction.isEnabled) {
        Based += FormattedIndex(element) -> this
      }
    }

    override protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr]) = {

      s"(${from._1})" -> Seq(showFormattedLImpl(from._2, break))
    }
  }

  case class BuiltInDiffMsg(
      element: Formatted,
      msg: String,
      infixOpt: Option[Formatted] = None
  ) extends Based {

    def index(): Unit = {

      if (TypeDiffsDetail.`builtin-msg`.isEnabled)
        Based += FormattedIndex(element) -> this
    }

    override protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr]) = {

      lazy val infixText = infixOpt match {
        case None => |
        case Some(ii) => " " + showFormattedLImpl(ii, break).flat + " "
      }

      val indented = msg
        .split("\n")
        .filter(_ != ";")

      s"(comparing <found>$infixText<required>)" -> indented.toSeq.map(v => FlatType(v))
    }
  }

  case class DefPosition(
      element: Formatted,
      srcInfo: String,
      quotes: Seq[String] = Nil
  ) extends Based {

    def index(): Unit = {

      if (TypeDetail.position.isEnabled)
        Based += FormattedIndex(element) -> this
    }

    override protected def formattedHeader_Body(break: Boolean): (String, Seq[TypeRepr]) = {

      s"(defined at $srcInfo)" -> quotes.map(quote => BrokenType(List(quote)))
    }
  }

  def formatTypeRaw(tpe: Type, top: Boolean): Formatted = {
    formatWithInfix(tpe, extractArgs(tpe), top)(formatType)
  }

  override def formatTypeImpl(tpe: Type, top: Boolean): Formatted = {

    tpe.typeArgs match {
      case List(t1, t2) =>
        val result =
          if (TypeDiffsDetail.disambiguation.isEnabled) {

            withDisambiguation(Nil, t1, t2) {
              formatTypeImplNoDisambiguation(tpe, top)
            }
          } else {

            formatTypeImplNoDisambiguation(tpe, top)
          }

        result match {
          case Infix(ii, left, right, _) =>
            val noApparentDiff = (left == right) && (t1 != t2)

            if (noApparentDiff || TypeDiffsDetail.`builtin-msg-always`.isEnabled) {

              BuiltInDiffMsg(
                result,
                TypeDiffView(t1, t2).builtInDiffMsg,
                Some(ii)
              ).index()
            }
          case _ =>
        }

        result
      case _ =>
        formatTypeImplNoDisambiguation(tpe, top)
    }

  }

  protected def formatTypeImplNoDisambiguation(tpe: Type, top: Boolean): Formatted = {
    val dtpe = dealias(tpe)

    val results = Seq(tpe, dtpe).distinct.map { t =>
      formatTypeRaw(t, top)
    }.distinct

    results match {
      case Seq(from, reduced) =>
        Reduction(reduced, "reduced from" -> from).index()
      case _ =>
    }

    val result = results.last

    TypeView(tpe).defPositionOpt.foreach { v =>
      DefPosition(
        result,
        v.shortText
      ).index()
    }

    result
  }

  override def formatDiffImpl(found: Type, req: Type, top: Boolean): Formatted = {

    if (TypeDiffsDetail.disambiguation.isEnabled) {

      val result = withDisambiguation(Nil, found, req) {
        formatDiffImplNoDisambiguation(found, req, top)
      }

      result match {
        case diff: Diff =>
          val noApparentDiff = (diff.left == diff.right) && (found != req)

          if (noApparentDiff || TypeDiffsDetail.`builtin-msg-always`.isEnabled) {

            BuiltInDiffMsg(
              diff,
              TypeDiffView(found, req).builtInDiffMsg
            ).index()
          }
        case _ =>
      }

      result
    } else {

      formatDiffImplNoDisambiguation(found, req, top)
    }
  }

  protected def formatDiffImplNoDisambiguation(found: Type, req: Type, top: Boolean): Formatted = {

    val reduced = Seq(found, req).map(dealias)
    val Seq(left, right) = reduced

    if (reduced.distinct.size == 1) {
      val only = reduced.head
      val result = formatType(only, top)

      val basedOn = Seq(found, req).distinct
        .map { tt =>
          formatTypeRaw(tt, top)
        }
        .distinct
        .flatMap { ft =>
          if (ft == result) None
          else Some("normalized from" -> ft)
        }

      basedOn.foreach { v =>
        Reduction(
          result,
          v
        ).index()
      }

      result
    } else {
      val result = {
        val noArgs = Seq(left, right).map { tt =>
          TypeView(tt).noArgType
        }

        if (noArgs.distinct.size == 1) {
          formatDiffInfix(left, right, top)
        } else {
          formatDiffSpecial(left, right, top).getOrElse {

            val result = formatDiffSimple(left, right)
            result
          }
        }
      }

      val basedOn = Seq(
        "left side reduced from" -> Seq(found, left),
        "right side reduced from" -> Seq(req, right)
      )
        .flatMap {
          case (clause, fts) =>
            if (fts.distinct.size == 1) None
            else {
              val formatted = fts.map { ft =>
                formatTypeRaw(ft, top)
              }.distinct
              if (formatted.size == 1) None
              else Some(clause -> formatted.head)
            }
        }

      basedOn.foreach { v =>
        Reduction(
          result,
          v
        ).index()
      }

      result
    }
  }

  case class ShowFormattedHelper(break: Boolean) {

    import scala.reflect.internal.TypeDebugging.AnsiColor._

    def _decideBreak(flat: FlatType, broken: BrokenType): TypeRepr = {

      if (break) decideBreak(flat, broken) else flat
    }

    def appendLastLine(lines: List[String], suffix: String): List[String] = {
      lines match {
        case Nil => List(suffix)
        case head :: Nil => List(head + suffix)
        case head :: tail => head :: appendLastLine(tail, suffix)
      }
    }

    def withVerticalDelimiter(v: TypeRepr): String = {
      v.lines
        .map { ll =>
          | + ll
        }
        .mkString("\n")
    }

    def showDiff(left: Formatted, right: Formatted): TypeRepr = {

      val (ll, rr) = (left, right) match {
        case (Qualified(lpath, lname), Qualified(rpath, rname)) if lname == rname =>
          val prefix = lpath.reverseIterator.zip(rpath.reverseIterator).takeWhile { case (l, r) => l == r }.size + 1
          FlatType(s"${qualifiedName(lpath.takeRight(prefix), lname).red}") ->
            FlatType(s"${qualifiedName(rpath.takeRight(prefix), rname).green}")

        case (left, right) =>
          _showFormattedL(left) ->
            _showFormattedL(right)
      }

      lazy val flat =
        FlatType(s"${ll.flat}${|}${rr.flat}")

      lazy val broken: BrokenType = {

        val Seq(_ll, _rr) = Seq(ll, rr).map { v =>
          v.indent.indent.indent.indent.indent.joinLines.trim
        }

        val result =
          s"""
             |found   : ${_ll}
             |${vertical_|}
             |required: ${_rr}""".stripMargin.trim

        BrokenType(result.split("\n").toList)
      }

      val result = _decideBreak(flat, broken)
      result
    }

    case class Tree(
        header: String,
        body: Seq[TypeRepr]
    ) {

      lazy val flat: String = {

        if (body.isEmpty) header
        else s"$header { ${body.map(v => v.flat).mkString(";")} }"
      }

      lazy val broken: Seq[String] = {
        val result = indentTree(List((header, body.flatMap(_.lines).toList, 0)), 1)

        result
      }
    }

    /**
      * If the args of an applied type constructor are multiline, create separate lines for the constructor name and the
      * closing bracket; else return a single line.
      */
    def showEnclosed(
        base: TypeRepr,
        args: List[TypeRepr],
        brackets: (String, String) = "[" -> "]",
        splitter: String = ","
    ): TypeRepr = {
      val flatArgs = args.map(_.flat).mkString(brackets._1, splitter + " ", brackets._2)
      val flat = FlatType(s"${base.flat}$flatArgs")

      def brokenArgs = args match {
        case head :: tail => tail.foldLeft(head.lines)((z, a) => appendLastLine(z, splitter) ::: a.lines)
        case _ => Nil
      }

      def broken = BrokenType(appendLastLine(base.lines, brackets._1) ::: indent(brokenArgs) ::: List(brackets._2))

      _decideBreak(flat, broken)
    }

    // TODO: let Based use this?
    def showTree(
        base: String,
        body: Seq[TypeRepr],
        brackets: (String, String) = "" -> ""
    ): TypeRepr = {

      def flat = FlatType {

        if (body.isEmpty) base
        else s"$base ${brackets._1}${body.map(v => v.flat).mkString(";")}${brackets._2}"
      }

      def broken = BrokenType {
        indentTree(List((base, body.flatMap(_.lines).toList, 0)), 1)
      }

      _decideBreak(flat, broken)
    }

    def showCompound(
        types: List[TypeRepr],
        infixText: String = "with"
    ): TypeRepr = {
      val infixWithSpace = s" $infixText "

      def flat = FlatType(types.map(_.flat).mkString(infixWithSpace))

      def broken = BrokenType(
        types.map(_.lines).reduceLeft((z, a) => appendLastLine(z, infixWithSpace) ::: a)
      )

      _decideBreak(flat, broken)
    }

    def _showFormattedL(v: Formatted): TypeRepr = showFormattedL(v, break)

    def showTuple(elems: List[Formatted]): TypeRepr = {
      val formattedElems = elems.map(_showFormattedL)

      elems match {
        case List(_) =>
          showEnclosed(FlatType("Tuple1"), formattedElems)
        case _ =>
          showEnclosed(FlatType(""), formattedElems, brackets = "(" -> ")")
      }
    }

    def apply(ft: Formatted): TypeRepr = {

      val raw = ft match {
        case Simple(name) => FlatType(name.name)
        case Qualified(path, name) => showFormattedQualified(path, name)
        case Applied(cons, args) => showEnclosed(_showFormattedL(cons), args.map(_showFormattedL))
        case tpe @ Infix(_, _, _, top) =>
          wrapParensRepr(
            if (break) breakInfix(flattenInfix(tpe)) else FlatType(flattenInfix(tpe).map(showFormatted).mkString(" ")),
            top
          )
        case UnitForm => FlatType("Unit")
        case FunctionForm(args, ret, top) =>
          FlatType(wrapParens(s"${showFuncParams(args.map(showFormatted))} => ${showFormatted(ret)}", top))
        case TupleForm(elems) =>
          showTuple(elems)

        case RefinedForm(elems, decls) =>
          val compound = showCompound(elems.map(_showFormattedL))

          val refined =
            if (decls.isEmpty)
              compound
            else if (truncateDecls(decls))
              showEnclosed(compound, List(FlatType("...")), brackets = " {" -> "}", splitter = ";")
            else
              showEnclosed(compound, decls.map(_showFormattedL), brackets = " {" -> "}", splitter = ";")

          refined

        case Diff(left, right) => showDiff(left, right)
        case Decl(sym, rhs) =>
          showTree(
            s"type ${showFormatted(sym)} =",
            Seq(_showFormattedL(rhs))
          )

        case DeclDiff(sym, left, right) =>
          val diff = showDiff(left, right)
          showTree(
            s"type ${showFormatted(sym)} =",
            Seq(diff)
          )

        case ByName(tpe) => FlatType(s"(=> ${showFormatted(tpe)})")
      }

      val index = FormattedIndex(ft)
      val basedOn = Based.getAll(index)

      val result = {

        basedOn match {
          case Nil =>
            raw
          case _ =>
            def flat = FlatType(raw.flat + " " + basedOn.map(_.flat).mkString(" "))

            def broken = BrokenType(raw.lines ++ basedOn.flatMap(_.broken))

            raw match {
              case _: BrokenType => broken
              case _ => _decideBreak(flat, broken)
            }
        }
      }

      result
    }

  }

  override def showFormattedLImpl(ft: Formatted, break: Boolean): TypeRepr = {
    ShowFormattedHelper(break)(ft)
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/SplainPlugin.scala
================================================
package splain

import scala.tools.nsc._
import scala.tools.nsc.typechecker.{Analyzer, MacroAnnotationNamers}

class SplainPlugin(val global: Global) extends SplainPluginLike with PluginSettings.Implicits {

  override lazy val pluginSettings: PluginSettings = PluginSettings(this.opts)

  lazy val splainAnalyzer: SplainAnalyzer =
    if (global.settings.YmacroAnnotations.value)
      new SplainAnalyzer(global, pluginSettings) with MacroAnnotationNamers
    else
      new SplainAnalyzer(global, pluginSettings)

  {
    val analyzerField = classOf[Global].getDeclaredField("analyzer")
    analyzerField.setAccessible(true)
    val oldAnalyzer = analyzerField.get(global).asInstanceOf[Analyzer]
    analyzerField.set(global, splainAnalyzer)

    val phasesSetMapGetter = classOf[Global]
      .getDeclaredMethod("phasesSet")

    val phasesSet = phasesSetMapGetter
      .invoke(global)
      .asInstanceOf[scala.collection.mutable.Set[SubComponent]]

    if (phasesSet.exists(_.phaseName == "typer")) {
      def subcomponentNamed(name: String) =
        phasesSet
          .find(_.phaseName == name)
          .head
      val oldScs @ List(oldNamer @ _, oldPackageobjects @ _, oldTyper @ _) = List(
        subcomponentNamed("namer"),
        subcomponentNamed("packageobjects"),
        subcomponentNamed("typer")
      )
      val newScs = List(splainAnalyzer.namerFactory, splainAnalyzer.packageObjects, splainAnalyzer.typerFactory)

      splainAnalyzer.migrateFrom(oldAnalyzer)

      phasesSet --= oldScs
      phasesSet ++= newScs
    }
    // TODO: remove them after AnalyzerPlugin interface becomes stable
  }

  override def init(options: List[String], error: String => Unit): Boolean = {
    def invalid(opt: String): Unit = error(
      s"splain: invalid option `$opt`, supported options are ${PluginSettings.nameToKey.map(kv => "`" + kv._1 + "`").mkString(", ")}"
    )
    def setOpt(key: String, value: String): Unit =
      if (opts.contains(key))
        opts.update(key, value)
      else
        invalid(key)
    options.foreach { opt =>
      opt.split(":").toList match {
        case key :: value :: Nil =>
          setOpt(key, value)
        case key :: Nil =>
          setOpt(key, "true")
        case _ =>
          invalid(opt)
      }
    }
    PluginSettings.Keys.enabled.get
  }
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/SplainPluginLike.scala
================================================
package splain

import scala.collection.mutable
import scala.tools.nsc._
import scala.tools.nsc.plugins.PluginComponent

trait SplainPluginLike extends plugins.Plugin {

  val name = "splain"
  val description = "better types and implicit errors"
  val components: List[PluginComponent] = Nil

  val opts: mutable.Map[String, String] = PluginSettings.nameToInitValue.to(mutable.Map)
}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/TyperCompatViews.scala
================================================
package splain

import scala.reflect.internal.util.{NoSourceFile, Position}

trait TyperCompatViews {
  self: SplainAnalyzer =>

  import global._

  case class TypeView(self: Type) {

    lazy val extractArgs: List[global.Type] = {

      self.typeArgs
    }

    lazy val noArgType: Type = if (extractArgs.nonEmpty) {
      self.typeConstructor
    } else {
      self
    }

    lazy val dealias_normal: Type = {

      if (isAux(self)) self
      else {
        val result = self.dealias.normalize
        result match {
          case p: PolyType =>
            val target = TypeView(p.resultType).dealias_normal
            val _p = p.copy(
              resultType = target
            )
            _p
          case _ =>
            result
        }
      }
    }

    lazy val definingSymbol: Symbol = {

      self match {
        case tt: SingletonType =>
          tt.termSymbol
        case _ =>
          self.typeSymbolDirect
      }
    }

    private lazy val parts = definingSymbol.ownerChain.reverse
      .map(_.name.decodedName.toString)
      .filterNot(part => part.startsWith("<") && part.endsWith(">"))

    lazy val (path, noArgShortName) = {

      val (ownerPath, _) = parts.splitAt(Math.max(0, parts.size - 1))

      val ownerPathPrefix = ownerPath.mkString(".")

      val ttString = TypeView(noArgType).typeToString

      if (ttString.startsWith(ownerPathPrefix)) {
        ownerPath -> ttString.stripPrefix(ownerPathPrefix).stripPrefix(".")
      } else {
        Nil -> ttString
      }
    }

    lazy val prefixFullName: String = {
      self.prefix.typeSymbol.fullNameString
    }

    // probably not useful, withDisambiguation + longString should cover most cases
    lazy val prefixContextIfNeeded: Option[String] = {

      prefixFullName.toLowerCase match {
        case "<root>" | "<empty>" | "<none>" => None
        case _ =>
          if (self.toLongString.startsWith(prefixFullName)) None
          else {
            Some(s"(in $prefixFullName)")
          }
      }
    }

    object _DefPosition {

      lazy val value: Position = definingSymbol.pos

      lazy val noSource: Boolean = value.source == NoSourceFile

      lazy val shortText: String = {

        val prefix = value.source.file.path + ":"

        val result = s"$prefix${value.line}:${value.column}"
        result
      }

      lazy val formattedText: String = {

        Position.formatMessage(value, "", shortenFile = false)
      }
    }

    def defPositionOpt: Option[_DefPosition.type] = Option(_DefPosition).filterNot(_.noSource)

    def typeToString: String = {

      import PluginSettings.TypeDetail

      def short = self.safeToString

      val base = {
        if (TypeDetail.long.isEnabled)
          scala.util.Try(self.toLongString).getOrElse(short)
        else
          short
      }

      val extraExistential =
        if (TypeDetail.existential.isEnabled)
          scala.util.Try(existentialContext(self)).toOption
        else
          None

      val extraAlias =
        if (TypeDetail.alias.isEnabled)
          scala.util.Try(explainAlias(self)).toOption
        else
          None

      (Seq(base) ++ extraExistential ++ extraAlias).mkString("")

    }
  }

  case class TypeDiffView(
      found: Type,
      req: Type
  ) {

    def map(fn: Type => Type): TypeDiffView =
      TypeDiffView(fn(found), fn(req))

    def toTuple[T](fn: Type => T): (T, T) = (fn(found), fn(req))

    // copied from eponymous variable in Scala compiler
    // apparently doesn't work after type arg stripped
//    lazy val easilyMistakable: Boolean = {
//
//      val foundWiden = found.widen
//      val reqWiden = req.widen
//      val sameNamesDifferentPrefixes =
//        foundWiden.typeSymbol.name == reqWiden.typeSymbol.name &&
//          foundWiden.prefix.typeSymbol != reqWiden.prefix.typeSymbol
//      val easilyMistakable =
//        sameNamesDifferentPrefixes &&
//          !req.typeSymbol.isConstant &&
//          finalOwners(foundWiden) && finalOwners(reqWiden) &&
//          !found.typeSymbol.isTypeParameterOrSkolem && !req.typeSymbol.isTypeParameterOrSkolem
//
//      easilyMistakable
//    }

    lazy val builtInDiffMsg: String = {
      val result = builtinFoundReqMsg(found, req)
      result
    }
  }

  case class DivergingImplicitErrorView(self: DivergentImplicitTypeError) {

    lazy val errMsg: String = {

      val formattedPT = showFormatted(formatType(self.pt0, top = false))

      s"diverging implicit expansion for type $formattedPT\nstarting with ${self.sym.fullLocationString}"
    }
  }

  case class PositionIndex(
      pos: Position
  ) {}

}


================================================
FILE: core/src/main/scala-2.13.7+/latest/splain/package.scala
================================================
import scala.tools.nsc.typechecker.splain.SimpleName
import scala.language.implicitConversions

package object splain {

  implicit def asSimpleName(s: String): SimpleName = SimpleName(s)
}


================================================
FILE: core/src/test/resources/splain/builtin/BasicSpec/__direct/check
================================================
newSource1.scala:13: error: implicit error;
!I e: ImplicitChain.II
ImplicitChain.g invalid because
!I impPar3: ImplicitChain.I1
――ImplicitChain.i1 invalid because
  !I impPar7: ImplicitChain.I3
  implicitly[II]
            ^
newSource1.scala:6: error: type mismatch;
  FoundReq.L┃FoundReq.R
  f(new L)
    ^
newSource1.scala:13: error: type mismatch;
  Long.VeryLong[
    Long.VeryLong[
      found   : Long.VeryLong[
                  Long.VeryLong[
                    Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]
                  ]
                ]
      ━━━━━━━━:
      required: Long.VeryLong2[
                  Long.VeryLong[
                    Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]
                  ]
                ]
    ]
  ]
  val str: Req = ??? : Found
                     ^
newSource1.scala:4: error: implicit error;
!I e:
  Long.VeryLong[
    Long.VeryLong[
      Long.VeryLong[
        Long.VeryLong[
          Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]
        ]
      ]
    ]
  ]
  implicitly[VeryLong[
            ^
newSource1.scala:7: error: type mismatch;
  Compound.y.type┃String
  f(y)
    ^
newSource1.scala:10: error: type mismatch;
  Compound.T┃<none> with Int┃String
  f(z)
    ^
newSource1.scala:4: error: implicit error;
!I e:
  Long.VeryLong[
    Long.VeryLong[
      Long.VeryLong[
        Long.VeryLong[
          Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[String]]]]
        ]
      ]
    ]
  ] {
    type A = Int;
    type B = Int;
    type C = Int;
    type D = Int;
    type E = Int;
    type F = Int;
    type G = Int;
    type H = Int
  }
  implicitly[VeryLong[
            ^
newSource1.scala:4: error: implicit error;
!I e:
  (
    Long.VeryLong[Int],
    Long.VeryLong[
      Long.VeryLong[
        Long.VeryLong[
          Long.VeryLong[
            Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[Int]]]]
          ]
        ]
      ]
    ]
  )
  implicitly[
            ^
newSource1.scala:16: error: type mismatch;
  (
    Long.VeryLong[Int],
    Long.VeryLong[
      Long.VeryLong[
        Long.VeryLong[
          Long.VeryLong[
            Long.VeryLong[Long.VeryLong[Long.VeryLong[Long.VeryLong[Int┃String]]]]
          ]
        ]
      ]
    ]
  )
  ) = x
      ^
newSource1.scala:11: error: type mismatch;
  B.this.t1.type┃B.this.t.TT
    val t2: t.TT = t1
                   ^
newSource1.scala:7: error: implicit error;
!I e: Bounds.F[Bounds.Arg]
Bounds.g invalid because
nonconformant bounds;
[Bounds.Arg, Nothing]
[A <: Bounds.Base, B]
  implicitly[F[Arg]]
            ^
newSource1.scala:4: error: implicit error;
!I ec: scala.concurrent.ExecutionContext
  Cannot find an implicit ExecutionContext. You might add
  an (implicit ec: ExecutionContext) parameter to your method.

  The ExecutionContext is used to configure how and on which
  thread pools asynchronous tasks (such as Futures) will run,
  so the specific ExecutionContext that is selected is important.

  If your application does not define an ExecutionContext elsewhere,
  consider using Scala's global ExecutionContext by defining
  the following:

  implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global

  long
  ^
newSource1.scala:10: error: implicit error;
!I e: String
f invalid because
!I impPar4:
  List[
    (
      InfixBreak.VeryLongTypeName ::::
      InfixBreak.VeryLongTypeName ::::
      InfixBreak.VeryLongTypeName ::::
      InfixBreak.VeryLongTypeName
    )
    ::::
    (InfixBreak.Short :::: InfixBreak.Short) ::::
    (
      InfixBreak.VeryLongTypeName ::::
      InfixBreak.VeryLongTypeName ::::
      InfixBreak.VeryLongTypeName ::::
      InfixBreak.VeryLongTypeName
    )
    ::::
    InfixBreak.VeryLongTypeName ::::
    InfixBreak.VeryLongTypeName ::::
    InfixBreak.VeryLongTypeName ::::
    InfixBreak.VeryLongTypeName
  ]
   (No implicit view available from Int => InfixBreak.T2.)

  implicitly[String]
            ^
newSource1.scala:11: error: implicit error;
!I e: DeepHole.C1[[Z]DeepHole.C2[DeepHole.T1,DeepHole.T2,Z]]
  implicitly[C1[T3]]
            ^
newSource1.scala:9: error: implicit error;
!I e: Aux.F.Aux[Aux.C, Aux.D]
Aux.f invalid because
!I impPar10: Aux.C
  implicitly[F.Aux[C, D]]
            ^
newSource1.scala:11: error: type mismatch;
  Refined.A with
  Refined.B with
  Refined.E┃Refined.C with
  Refined.F┃<none> {
    type X = Int┃String;
    type Y = String;
    type Z = <none>┃String
  }
  f(x)
    ^
newSource1.scala:21: error: type mismatch;
  Refined.E┃Refined.C with
  Refined.F┃<none> with
  Refined.Sub1.A with
  Refined.Sub1.Sub2.B {
    type X = Int┃String;
    type Y = String;
    type Z = <none>┃String
  }
      f(x)
        ^
newSource1.scala:9: error: implicit error;
!I e: Refined.Node {type T <: Int}
  implicitly[NodeLt[Int]]
            ^
newSource1.scala:11: error: type mismatch;
  Int(1)┃Refined.Node {type T <: Int}
  val k: NodeLt[Int] = 1
                       ^
newSource1.scala:10: error: implicit error;
!I e: Refined.Node{type T = _$2} forSome { type _$2 <: Int }
  implicitly[NodeLt[Int]]
            ^
newSource1.scala:12: error: type mismatch;
  Int(1)┃Refined.Node{type T = _$2} forSome { type _$2 <: Int }
  val k: NodeLt[Int] = 1
                       ^
newSource1.scala:25: error: type mismatch;
  C.X.Y.T┃B.X.Y.T
  f(x: C.X.Y.T)
     ^
newSource1.scala:6: error: type mismatch;
  Int┃(=> Foo.A) => Foo.B
  f(1: Int)
     ^
newSource1.scala:3: error: type mismatch;
  String┃Tuple1[String]
  val a: Tuple1[String] = "Tuple1": String
                                  ^
newSource1.scala:7: error: implicit error;
!I e: SingleImp.a.type *** SingleImp.b.type
  implicitly[a.type *** b.type]
            ^
newSource1.scala:8: error: implicit error;
!I e: a.type *** b.type
    implicitly[a.type *** b.type]
              ^
newSource1.scala:6: error: implicit error;
!I e: a.type *** b.type
    implicitly[a.type *** b.type]
              ^
newSource1.scala:5: error: implicit error;
!I ev: scala.math.Ordering[Object]
  No implicit Ordering[Object] found to build a SortedSet[Object]. You may want to upcast to a Set[Int] first by calling `unsorted`.

Ordering.ordered invalid because
!I asComparable: Object => Comparable[Any]
  No implicit view available from Object => Comparable[_ >: Object].

Ordering.comparatorToOrdering invalid because
!I cmp: java.util.Comparator[Object]
    ms.map(_ => o)
          ^
newSource1.scala:9: error: implicit error;
!I e: List[a.TypeA]
   (No implicit view available from Int => a.TypeA.)

        implicitly[List[TypeA]]
                  ^
newSource1.scala:10: error: implicit error;
!I e: Seq[a.b.TypeB]
   (No implicit view available from Int => a.b.TypeB.)

        implicitly[Seq[TypeB]]
                  ^
newSource1.scala:11: error: implicit error;
!I e: Iterable[a.b.c.TypeC]
        implicitly[Traversable[TypeC]]
                  ^
newSource1.scala:12: error: implicit error;
!I e: Iterator[a.b.c.d.TypeD]
        implicitly[Iterator[TypeD]]
                  ^


================================================
FILE: core/src/test/resources/splain/builtin/MaxRefinedSpec/__direct/check
================================================
newSource1.scala:7: error: type mismatch;
  TruncRefined.D┃TruncRefined.C {
    type X = TruncRefined.C;
    type Y = TruncRefined.D
  }
  f(new D { type X = C; type Y = D })
    ^
newSource1.scala:7: error: type mismatch;
  TruncRefined.D┃TruncRefined.C {...}
  f(new D { type X = C; type Y = D })
    ^

================================================
FILE: core/src/test/resources/splain/builtin/VerboseTreeSpec/__direct/check
================================================
newSource1.scala:28: error: implicit error;
!I e: tpes.I1
i1a invalid because
!I p: tpes.I2
――i2 invalid because
  !I p: tpes.I3
――――i3a invalid because
    !I p: tpes.I4
――――――i4 invalid because
      !I p: tpes.I5
――――――――i5 invalid because
        !I p: tpes.I6
――――――――――i6a invalid because
          !I p: tpes.I7
――――――――――――i7 invalid because
            !I p: tpes.I8
――――――――――――――i8 invalid because
              !I p: tpes.I9
――――――――――i6b invalid because
          !I p: tpes.I8
――――――――――――i8 invalid because
            !I p: tpes.I9
――――i3b invalid because
    !I p: tpes.I4
――――――i4 invalid because
      !I p: tpes.I5
――――――――i5 invalid because
        !I p: tpes.I6
――――――――――i6a invalid because
          !I p: tpes.I7
――――――――――――i7 invalid because
            !I p: tpes.I8
――――――――――――――i8 invalid because
              !I p: tpes.I9
――――――――――i6b invalid because
          !I p: tpes.I8
――――――――――――i8 invalid because
            !I p: tpes.I9
i1b invalid because
!I p: tpes.I6
――i6a invalid because
  !I p: tpes.I7
――――i7 invalid because
    !I p: tpes.I8
――――――i8 invalid because
      !I p: tpes.I9
――i6b invalid because
  !I p: tpes.I8
――――i8 invalid because
    !I p: tpes.I9
  implicitly[I1]
            ^
newSource1.scala:28: error: implicit error;
!I e: tpes.I1
i1a invalid because
!I p: tpes.I2
⋮
――i3a invalid because
  !I p: tpes.I4
  ⋮
――――i6a invalid because
    !I p: tpes.I7
    ⋮
――――――――i8 invalid because
        !I p: tpes.I9
――――i6b invalid because
    !I p: tpes.I8
――――――i8 invalid because
      !I p: tpes.I9
――i3b invalid because
  !I p: tpes.I4
  ⋮
――――i6a invalid because
    !I p: tpes.I7
    ⋮
――――――――i8 invalid because
        !I p: tpes.I9
――――i6b invalid because
    !I p: tpes.I8
――――――i8 invalid because
      !I p: tpes.I9
i1b invalid because
!I p: tpes.I6
――i6a invalid because
  !I p: tpes.I7
  ⋮
――――――i8 invalid because
      !I p: tpes.I9
――i6b invalid because
  !I p: tpes.I8
――――i8 invalid because
    !I p: tpes.I9
  implicitly[I1]
            ^

================================================
FILE: core/src/test/resources/splain/plugin/ErrorsCompatSpec/byname/code.scala
================================================
object ByName {
  type A

  def f(
      implicit
      a: => A
  ): Unit = ???

  {
    implicit val a: A = ???

    f
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/ambiguous/code.scala
================================================
object Ambiguous {
  implicit val c1: C = ???
  implicit val c2: C = ???
  implicit def f1: D = ???
  implicit def f2: D = ???
  implicitly[D]
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/ambiguous/error
================================================
ambiguous implicit values:
 both method f1 in object Ambiguous of type types.D
 and method f2 in object Ambiguous of type types.D
 match expected type types.D


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/bounds/code.scala
================================================
object NonconformantBounds {
  trait F[A]
  implicit def f[A <: C, B]: F[A] = ???
  implicitly[F[D *** C]]
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/bounds/error
================================================
newSource1.scala:12: error: implicit error;
!I e: NonconformantBounds.F[types.D *** types.C]
NonconformantBounds.f invalid because
nonconformant bounds;
[types.D *** types.C, Nothing]
[A <: types.C, B]
  implicitly[F[D *** C]]
            ^

================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/chain/code.scala
================================================
import shapeless.Poly1

object pol extends Poly1

trait Low {
  trait I1
  trait I2
  trait I3
  trait I4
  trait F[X[_]]
  implicit def lowI1: I1 = ???
  implicit def lowI2: I2 = ???
}

object ImplicitChain extends Low {
  type T1 = C *** D >:< (C with D { type A = D; type B = C })
  type T2 = D *** ((C >:< C) *** (D => Unit))
  type T3 = (D *** (C *** String)) >:< ((C, D, C) *** D)
  type T4 = C *** D *** C
  type T5 = D *** C >:< D
  type T6 = pol.Case.Aux[Int, String]
  type T7 = D >:< C >:< D
  implicit def i1(
      implicit
      impPar7: I3
  ): I1 = ???
  implicit def i2a(
      implicit
      impPar8: I3
  ): I2 = ???
  implicit def i2b(
      implicit
      impPar8: I3
  ): I2 = ???
  implicit def i4(
      implicit
      impPar9: I2
  ): I4 = ???
  implicit def t7(
      implicit
      impPar14: F[({ type λ[X] = Either[Int, X] })#λ]
  ): T7 = ???
  implicit def t5(
      implicit
      impPar13: pol.Case.Aux[Int, String]
  ): T5 = ???
  implicit def t4(
      implicit
      impPar12: T5
  ): T4 = ???
  implicit def t3a(
      implicit
      impPar11: T7
  ): T3 = ???
  implicit def t3b(
      implicit
      impPar10: T4
  ): T3 = ???
  implicit def f(
      implicit
      impPar4: I4,
      impPar2: T3
  ): T2 = ???
  implicit def g(
      implicit
      impPar3: I1,
      impPar1: T2
  ): T1 = ???
  implicitly[T1]
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/chain/error
================================================
newSource1.scala:77: error: implicit error;
!I e:
  (types.C *** types.D) >:<
  types.C with types.D {type A = types.D; type B = types.C}
g invalid because
!I impPar1: types.D *** (types.C >:< types.C) *** (types.D => Unit)
――f invalid because
  !I impPar2:
    (types.D *** types.C *** String) >:<
    (types.C, types.D, types.C) ***
    types.D
――――t3a invalid because
    !I impPar11: (types.D >:< types.C) >:< types.D
――――――t7 invalid because
      !I impPar14: ImplicitChain.F[[X]scala.util.Either[Int,X]]
――――t3b invalid because
    !I impPar10: (types.C *** types.D) *** types.C
――――――t4 invalid because
      !I impPar12: (types.D *** types.C) >:< types.D
――――――――t5 invalid because
        !I impPar13: pol.Case.Aux[Int, String]
  implicitly[T1]
            ^

================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/higherKindArg/code.scala
================================================
import shapeless.Poly1

object pol extends Poly1

object Functors {

  trait F[X[_]]

  implicitly[F[({ type λ[X] = Either[Int, X] })#λ]]
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/higherKindArg/error
================================================
newSource1.scala:17: error: implicit error;
!I e: Functors.F[[X]scala.util.Either[Int,X]]
  implicitly[F[({ type λ[X] = Either[Int, X] })#λ]]
            ^

================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/implicit-ctrl-char/code.scala
================================================
import annotation.implicitNotFound

object Annotation {

  trait Arg

  @implicitNotFound("A\n   ┃ B\n  ┃ C")
  trait F[A]

  trait G[A]

  implicit def f[A](
      implicit
      ev: F[A]
  ): G[A] = ???

  implicitly[G[Arg]]
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/implicit-ctrl-char/error
================================================
newSource1.scala:25: error: implicit error;
!I e: Annotation.G[Annotation.Arg]
Annotation.f invalid because
!I ev: Annotation.F[Annotation.Arg]
  A
     ┃ B
    ┃ C

  implicitly[G[Arg]]
            ^

================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/lazy/code.scala
================================================
import shapeless._
import shapeless.ops.hlist._

object LazyImp {
  implicit def dc(
      implicit
      a: C *** D
  ): D *** C = ???
  implicit def d(
      implicit
      a: D *** C
  ): D = ???
  implicit def c(
      implicit
      a: Lazy[D]
  ): C = ???
  implicitly[C]
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/lazy/error
================================================
newSource1.scala:25: error: implicit error;
!I e: types.C
c invalid because
!I a: shapeless.Lazy[types.D]
  could not find Lazy implicit value of type types.D

――d invalid because
  !I a: types.D *** types.C
――――dc invalid because
    !I a: types.C *** types.D
  implicitly[C]
            ^

================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/member/code.scala
================================================
object NotAMember {
  val a = new (C *** D >:< D *** C)
  a.attr
}


================================================
FILE: core/src/test/resources/splain/plugin/PluginSpec/member/error
================================================
newSource1.scala:11: error: value attr is not a member of types.C *** types.D >:< types.D *** types.C
  a.attr
    ^

================================================
FILE: core/src/test/resources/splain/plugin/ShapelessSpec/lazyImplicit/code.scala
================================================
import shapeless.Lazy

object DivergingImplicits {

  type C
  type D

  object Diverging {

    trait ::[A, B]

    implicit def f[A, B](
        implicit
        ii: Lazy[Int]
    ): A :: B = ???

    implicitly[C :: D]
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/ShapelessSpec/lazyImplicit/error
================================================
newSource1.scala:25: error: implicit error;
!I e: DivergingImplicits.C :: DivergingImplicits.D
Diverging.f invalid because
!I ii: shapeless.Lazy[Int]
  could not find Lazy implicit value of type Int

    implicitly[C :: D]
              ^

================================================
FILE: core/src/test/resources/splain/plugin/ShapelessSpec/record/code.scala
================================================
import shapeless._
import shapeless.record._
import shapeless.syntax.singleton._

object ShapelessRecord {
  object Key
  object Value

  type Message = Record.`'sym -> String, "str" -> Value.type, Key -> Int`.T

  def show(message: Message) = ???

  val a =
    ('sym ->> "value") ::
      ("str" ->> Value) ::
      (Key ->> 42L) :: HNil

  show(a)
}


================================================
FILE: core/src/test/resources/splain/plugin/ShapelessSpec/record/error
================================================
newSource1.scala:26: error: type mismatch;
  ('sym ->> String) ::
  ("str" ->> ShapelessRecord.Value.type) ::
  (ShapelessRecord.Key.type ->> Long┃Int) ::
  shapeless.HNil
  show(a)
       ^

================================================
FILE: core/src/test/resources/splain/plugin/ShapelessSpec/witness-value/code.scala
================================================
import shapeless._
import shapeless.ops.hlist._

object WitnessImp {
  def fn[A, B](a: A, b: B)(
      implicit
      ev: A *** B
  ) = ???

  fn(Witness(3).value, Witness(4).value)
}


================================================
FILE: core/src/test/resources/splain/plugin/ShapelessSpec/witness-value/error
================================================
newSource1.scala:18: error: implicit error;
!I ev: Int(3) *** Int(4)
  fn(Witness(3).value, Witness(4).value)
    ^

================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular/code.scala
================================================
object DivergingImplicits {

  type C
  type D

  object Circular {
    implicit def f(
        implicit
        c: C
    ): D = ???

    implicit def g(
        implicit
        d: D
    ): C = ???

    implicitly[C]
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular/error
================================================
newSource1.scala:17: error: implicit error;
!I e: DivergingImplicits.C
g invalid because
!I d: DivergingImplicits.D
diverging implicit expansion for type DivergingImplicits.D
starting with method f in object Circular
――f invalid because
  !I c: DivergingImplicits.C
――――g invalid because
    !I d: DivergingImplicits.D
    diverging implicit expansion for type DivergingImplicits.D
    starting with method f in object Circular
    implicitly[C]
              ^

================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular-recoverable/code.scala
================================================
object DivergingImplicits {

  type C
  type D

  trait LowLevel {

    implicit def f2: D = ???
  }

  object Circular extends LowLevel {
    implicit def f(
        implicit
        c: C
    ): D = ???

    implicit def g(
        implicit
        d: D
    ): C = ???

    implicitly[C]
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging/code.scala
================================================
object DivergingImplicits {

  type C
  type D

  object Diverging {
    trait ::[A, B]

    implicit def f[A, B](
        implicit
        ii: Int :: A :: B
    ): A :: B = ???

    implicit def g[A, B]: Int :: Int :: Int :: A :: B = ???

    implicitly[C :: D]
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging/error
================================================
newSource1.scala:16: error: implicit error;
!I e: DivergingImplicits.C :: DivergingImplicits.D
Diverging.f invalid because
!I ii: Int :: DivergingImplicits.C :: DivergingImplicits.D
――Diverging.f invalid because
  !I ii: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D
  diverging implicit expansion for type (Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D)
  starting with method f in object Diverging
――――Diverging.f invalid because
    !I ii: Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D
    diverging implicit expansion for type (Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D)
    starting with method g in object Diverging
    implicitly[C :: D]
              ^

================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging-compact/code.scala
================================================
object DivergingImplicits {

  type C
  type D

  object Diverging {
    trait ::[A, B]

    implicit def f[A, B](
        implicit
        ii: Int :: A :: B
    ): A :: B = ???

    implicit def g[A, B]: Int :: Int :: Int :: A :: B = ???

    implicitly[C :: D]
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging-compact/error
================================================
newSource1.scala:16: error: implicit error;
!I e: DivergingImplicits.C :: DivergingImplicits.D
Diverging.f invalid because
!I ii: Int :: DivergingImplicits.C :: DivergingImplicits.D
⋮
――Diverging.f invalid because
  !I ii: Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D
  diverging implicit expansion for type (Int :: Int :: Int :: DivergingImplicits.C :: DivergingImplicits.D)
  starting with method g in object Diverging
    implicitly[C :: D]
              ^

================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/self/code.scala
================================================
object DivergingImplicits {

  type C
  type D

  object Endo {
    implicit def f(
        implicit
        c: C
    ): C = ???

    implicitly[C]
  }
}


================================================
FILE: core/src/test/resources/splain/plugin/VImplicitDivergingSpec/self/error
================================================
newSource1.scala:12: error: implicit error;
!I e: DivergingImplicits.C
f invalid because
!I c: DivergingImplicits.C
diverging implicit expansion for type DivergingImplicits.C
starting with method f in object Endo
――f invalid because
  !I c: DivergingImplicits.C
  diverging implicit expansion for type DivergingImplicits.C
  starting with method f in object Endo
    implicitly[C]
              ^

================================================
FILE: core/src/test/resources/splain/plugin/VTypeDetailPositionSpec/__direct/check
================================================
newSource1.scala:12: error: implicit error;
!I e: Diff.e1.VV =:= String
  Cannot prove that Diff.e1.VV =:= String.

  implicitly[e1.VV =:= String]
            ^
newSource1.scala:13: error: type mismatch;
  String┃Diff.e1.VV
  val x: e1.VV = ??? : String
                     ^
newSource1.scala:12: error: implicit error;
!I e: Diff.e1.VV (defined at newSource1.scala:9:10) =:= String
  Cannot prove that Diff.e1.VV =:= String.

  implicitly[e1.VV =:= String]
            ^
newSource1.scala:13: error: type mismatch;
  String┃Diff.e1.VV (defined at newSource1.scala:9:10)
  val x: e1.VV = ??? : String
                     ^


================================================
FILE: core/src/test/resources/splain/plugin/VTypeDetailReductionSpec/__direct/check
================================================
newSource1.scala:8: error: implicit error;
!I e: Option[Int] =:= Option[String]
  Cannot prove that FoundReqVsImplicit.vecInt.Head =:= Option[String].

implicitly[vecInt.Head =:= Option[String]]
          ^
newSource1.scala:10: error: type mismatch;
  Option[String┃Int]
val x: vecInt.Head = ??? : Option[String]
                         ^
newSource1.scala:8: error: implicit error;
!I e:
  Option[Int] (reduced from) { FoundReqVsImplicit.vecInt.Head } =:=
  Option[String]
  Cannot prove that FoundReqVsImplicit.vecInt.Head =:= Option[String].

implicitly[vecInt.Head =:= Option[String]]
          ^
newSource1.scala:10: error: type mismatch;
  Option[String┃Int]
  ――(right side reduced from)
    FoundReqVsImplicit.vecInt.Head
val x: vecInt.Head = ??? : Option[String]
                         ^

================================================
FILE: core/src/test/resources/splain/plugin/VTypeDetailSpec/__direct/check
================================================

newSource1.scala:15: error: type mismatch;
  Test.F[Test.a.type┃a.type]
      wrongf(new A)(new F[AA])
                    ^
newSource1.scala:16: error: implicit error;
!I b: Test.F[a.type]
      wrongf(new A)
            ^
newSource1.scala:15: error: type mismatch;
  Test.F[
    found   : Test.a.type (with underlying type Test.A)
    ━━━━━━━━:
    required: a.type (with underlying type a.type)
  ]
      wrongf(new A)(new F[AA])
                    ^
newSource1.scala:16: error: implicit error;
!I b: Test.F[a.type (with underlying type a.type)]
      wrongf(new A)
            ^
newSource1.scala:15: error: type mismatch;
  Test.F[
    found   : Test.a.type (with underlying type Test.A)
    ━━━━━━━━:
    required: a.type (with underlying type a.type) where val a: Test.A
  ]
      wrongf(new A)(new F[AA])
                    ^
newSource1.scala:16: error: implicit error;
!I b: Test.F[a.type (with underlying type a.type) where val a: Test.A]
      wrongf(new A)
            ^
newSource1.scala:15: error: type mismatch;
  Test.F[
    found   : Test.a.type (with underlying type Test.A)
    ━━━━━━━━:
    required: a.type (with underlying type a.type) where val a: Test.A
    ――(left side reduced from)
      Test.AA
  ]
      wrongf(new A)(new F[AA])
                    ^
newSource1.scala:16: error: implicit error;
!I b: Test.F[a.type (with underlying type a.type) where val a: Test.A]
      wrongf(new A)
            ^

newSource1.scala:15: error: type mismatch;
  Test.F[
    found   : Test.a.type (with underlying type Test.A)
              ――(defined at newSource1.scala:10:11)
    ━━━━━━━━:
    required: a.type (with underlying type a.type) where val a: Test.A
              ――(defined at newSource1.scala:13:18)
    ――(left side reduced from)
      Test.AA
  ]
      wrongf(new A)(new F[AA])
                    ^
newSource1.scala:16: error: implicit error;
!I b:
  Test.F[
    a.type (with underlying type a.type) where val a: Test.A
    ――(defined at newSource1.scala:13:18)
  ]
  ――(defined at newSource1.scala:8:13)
      wrongf(new A)
            ^

newSource1.scala:15: error: type mismatch;
  Test.F[
    found   : Test.a.type (with underlying type Test.A)
              ――(defined at newSource1.scala:10:11)
    ━━━━━━━━:
    required: a.type (with underlying type a.type) where val a: Test.A
              ――(defined at newSource1.scala:13:18)
    ――(left side reduced from)
      Test.AA
    (which expands to)  Test.a.type
  ]
      wrongf(new A)(new F[AA])
                    ^
newSource1.scala:16: error: implicit error;
!I b:
  Test.F[
    a.type (with underlying type a.type) where val a: Test.A
    ――(defined at newSource1.scala:13:18)
  ]
  ――(defined at newSource1.scala:8:13)
      wrongf(new A)
            ^
newSource1.scala:5: error: implicit error;
!I e: String :: Int :: Boolean
      implicitly[K]
                ^
newSource1.scala:7: error: type mismatch;
  String("abc")┃String :: Int :: Boolean
      def v: K = "abc"
                 ^
newSource1.scala:5: error: implicit error;
!I e: String :: Int :: Boolean (reduced from) { Test.K }
      implicitly[K]
                ^
newSource1.scala:7: error: type mismatch;
  String("abc")┃String :: Int :: Boolean (reduced from) { Test.K }
  ――(right side reduced from)
    Test.K
      def v: K = "abc"
                 ^


================================================
FILE: core/src/test/resources/splain/plugin/VTypeDiffsDetailSpec/__direct/check
================================================
newSource1.scala:6: error: type mismatch;
  Long┃Long
        else add2(x.head, y.head) :: add(x.tail, y.tail)
                    ^
newSource1.scala:6: error: type mismatch;
  Long┃Long
        else add2(x.head, y.head) :: add(x.tail, y.tail)
                            ^
newSource1.scala:16: error: implicit error;
!I ev: Long =:= Long
  Cannot prove that Long =:= Long.

        add2(x.head)
            ^
newSource1.scala:27: error: implicit error;
!I ev: Long <:< Long
  Cannot prove that Long <:< Long.

        add2(x.head)
            ^
newSource1.scala:6: error: type mismatch;
  Long(in method add)┃scala.Long
        else add2(x.head, y.head) :: add(x.tail, y.tail)
                    ^
newSource1.scala:6: error: type mismatch;
  Long(in method add)┃scala.Long
        else add2(x.head, y.head) :: add(x.tail, y.tail)
                            ^
newSource1.scala:16: error: implicit error;
!I ev: Long(in method add) =:= scala.Long
  Cannot prove that Long =:= Long.

        add2(x.head)
            ^
newSource1.scala:27: error: implicit error;
!I ev: Long(in method add) <:< scala.Long
  Cannot prove that Long <:< Long.

        add2(x.head)
            ^

newSource1.scala:6: error: type mismatch;
  Long(in method add)┃scala.Long
  ――(comparing <found>┃<required>)
     found   : Long(in method add)
     required: scala.Long
        else add2(x.head, y.head) :: add(x.tail, y.tail)
                    ^
newSource1.scala:6: error: type mismatch;
  Long(in method add)┃scala.Long
  ――(comparing <found>┃<required>)
     found   : Long(in method add)
     required: scala.Long
        else add2(x.head, y.head) :: add(x.tail, y.tail)
                            ^
newSource1.scala:16: error: implicit error;
!I ev:
  Long(in method add) =:= scala.Long
  ――(comparing <found> =:= <required>)
     found   : Long(in method add)
     required: scala.Long
  Cannot prove that Long =:= Long.

        add2(x.head)
            ^
newSource1.scala:27: error: implicit error;
!I ev:
  Long(in method add) <:< scala.Long
  ――(comparing <found> <:< <required>)
     found   : Long(in method add)
     required: scala.Long
  Cannot prove that Long <:< Long.

        add2(x.head)
            ^
newSource1.scala:27: error: implicit error;
!I ev:
  Long(in method add) <:< scala.Long
  ――(comparing <found><:<<required>)
     found   : Long(in method add)
     required: scala.Long
  Cannot prove that Long <:< Long.

        add2(x.head)
            ^

================================================
FILE: core/src/test/resources/splain/plugin/ZIOSpec/zlayer/code.scala
================================================
import zio._

object layers {

  trait Service1
  trait Service2
  trait Service3
  trait Service4

  val service1 = ZLayer.succeed(new Service1 {})

  val service2 = ZLayer.succeed(new Service2 {})

  val service3 = ZLayer.fromService((_: Service1) => new Service3 {})

  val service4 = ZLayer.succeed(new Service4 {})

  val services: ULayer[Has[Service1] with Has[Service2] with Has[Service3] with Has[Service4]] =
    service1 ++ service2 >+> service3 // ++ service4
}


================================================
FILE: core/src/test/resources/splain/plugin/ZIOSpec/zlayer/error
================================================
newSource1.scala:19: error: type mismatch;
  zio.ZLayer[
    Any,
    Nothing,
    <none>┃zio.Has[layers.Service4] with
    zio.Has[layers.Service1] with
    zio.Has[layers.Service2] with
    zio.Has[layers.Service3]
  ]
    service1 ++ service2 >+> service3 // ++ service4
                         ^

================================================
FILE: core/src/test/scala/splain/PlainPrettifier.scala
================================================
//package splain
//
//import org.scalactic.{Prettifier, PrettyPair}
//
//object PlainPrettifier extends Prettifier {
//
//  override def apply(o: Any): String = Prettifier.basic.apply(o)
//
//  override def apply(left: Any, right: Any): PrettyPair = {
//    PrettyPair(apply(left), apply(right), None)
//  }
//}


================================================
FILE: core/src/test/scala/splain/ScalacticSpike.scala
================================================
//package splain
//
//import org.scalatest.Ignore
//
//@Ignore
//class ScalacticSpike extends SpecBase {
//
//  it("can diff") {
//
//    val a1 =
//      """
//        |     case (s1: String, s2: String) => StringDiffer.difference(s1, s2, prettifier)
//        |      case (s1: scala.collection.GenMap[Any, Any], s2: scala.collection.GenMap[Any, Any]) => GenMapDiffer.difference(s1, s2, prettifier)
//        |      case (s1: scala.collection.GenSeq[_], s2: scala.collection.GenSeq[_]) => GenSeqDiffer.difference(s1, s2, prettifier)
//        |""".stripMargin
//
//    val a2 =
//      """
//        |     case (s1: String, s2: String) => StringDiffer.difference(s1, s2, prettifier)
//        |      case (s1: scala.collllection.GenMap[Any, Any], s2: scala.collection.GenMap[Any, Any]) => GenMapDiffer.difference(s1, s2, prettifier)
//        |      case (s1: scala.collection.GenSeq[_], s2: scala.collection.GenSeq[_]) => GenSeqDiffer.difference(s1, s2, prettifier)
//        |""".stripMargin
//
//    val vv = PlainPrettifier.apply(a1, a2)
//
//    println(vv)
//  }
//}


================================================
FILE: core/src/test/scala/splain/SpecBase.scala
================================================
package splain

import org.scalatest.funspec.AnyFunSpec
import org.slf4j.LoggerFactory

import scala.util.Try

trait SpecBase extends AnyFunSpec with TestHelpers {

  protected def _it: ItWord = it
}

object SpecBase {

  trait Direct extends SpecBase {

    // will use reflection to discover all type `() => String` method under this instance
    lazy val codeToName: Map[String, String] = {

      val allMethods = this.getClass.getMethods
      val methods = allMethods.filter { method =>
        method.getParameterCount == 0 &&
        method.getReturnType == classOf[String]
      }

      val methodSeq = methods.flatMap { method =>
        Try {
          val code = method.invoke(this).asInstanceOf[String]
          code -> method.getName
        }.toOption
      }.toSeq

      Map(methodSeq: _*)
    }

    def getName(code: String, nameOverride: String, profile: Profile = Profile.default): String = {
      val baseName =
        if (nameOverride.nonEmpty) nameOverride
        else codeToName(code)

      val name =
        if (profile == Profile.default) baseName
        else s"$baseName - $profile"

      name
    }

    lazy val runner: DirectRunner = DirectRunner()

    def check(
        code: String,
        profile: Profile = Profile.default,
        nameOverride: String = "",
        numberOfErrors: Int = 1,
        verbose: Boolean = false
    ): Unit = {

      val name = getName(code, nameOverride, profile)

      val cc = DirectCase(code, profile)

      val from = runner.pointer.getAndAdd(numberOfErrors)
      val until = runner.pointer.get()
      val groundTruth = runner.groundTruths.slice(from, until).mkString("\n")

      _it(name) {
        val error = cc.compileWith.compileError()
        error must_== groundTruth

        if (verbose)
          LoggerFactory
            .getLogger(this.getClass)
            .info(
              "\n" + error
            )
      }
    }

    def skip(
        code: String,
        profile: Profile = Profile.default,
        nameOverride: String = "",
        numberOfBlocks: Int = 1
    ): Unit = {

      val name = getName(code, nameOverride, profile)

      runner.pointer.getAndAdd(numberOfBlocks)

      ignore(name) {}
    }
  }

  trait File extends SpecBase {

    def check(
        name: String,
        file: String = "",
        profile: Profile = Profile.default
    )(
        check: CheckFile
    ): Unit = {

      val _file =
        if (file.isEmpty) name
        else file

      val testName = Seq(name, file).filter(_.nonEmpty).mkString(" - ")

      _it(testName) {

        check(FileCase(_file, profile))
      }
    }

    def skip(
        name: String,
        file: String = "",
        setting: Profile = Profile.default
    )(
        check: CheckFile
    ): Unit = {

      val _file =
        if (file.isEmpty) name
        else file

      val testName = Seq(name, file).filter(_.nonEmpty).mkString(" - ")

      ignore(testName) {

        check(FileCase(_file, setting))
      }
    }
  }
}


================================================
FILE: core/src/test/scala/splain/builtin/BasicSpec.scala
================================================
package splain.builtin

import splain.SpecBase

class BasicSpec extends SpecBase.Direct with BasicFixture {

  check(chain)

  describe("#121") {

    check(foundReq)

    check(longFoundReq)
  }

  check(longArg)

  describe("#34") {
    check(compoundDiff, numberOfErrors = 2)
  }

  describe("#111") {

    check(LongRefined)

    check(LongTuple)

    check(foundReqLongTuple)
  }

  check(foundReqSameSymbol)

  check(bounds)

  check(longAnnotationMessage)

  check(longInfix)

  check(deeplyNestedHole)

  check(auxType)

  check(refined1, numberOfErrors = 2)

  check(refined2, numberOfErrors = 2)

  check(refined3, numberOfErrors = 2)

  check(disambiguateQualified)

  check(bynameParam)

  check(tuple1)

  check(singleType)

  check(singleTypeInFunction)

  check(singleTypeWithFreeSymbol)

  check(parameterAnnotation)

  check(shorthandTypes, numberOfErrors = 4)
}


================================================
FILE: core/src/test/scala/splain/builtin/BasicXSource3Spec.scala
================================================
package splain.builtin

class BasicXSource3Spec extends BasicSpec {

  override lazy val suiteCanonicalName: String = classOf[BasicSpec].getCanonicalName

  override def defaultExtraSetting: String = "-Xsource:3"
}


================================================
FILE: core/src/test/scala/splain/builtin/MaxRefinedSpec.scala
================================================
package splain.builtin

import splain.SpecBase

class MaxRefinedSpec extends SpecBase.Direct {

  def truncrefined: String = """
object TruncRefined
{
  class C
  trait D
  type CAux[A] = C { type X = C; type Y = D }
  def f(arg1: CAux[D]) = ???
  f(new D { type X = C; type Y = D })
}

  """

  check(truncrefined)

  check(truncrefined, profile = "-Vimplicits-max-refined 5")
}


================================================
FILE: core/src/test/scala/splain/builtin/VerboseTreeSpec.scala
================================================
package splain.builtin

import splain.SpecBase

class VerboseTreeSpec extends SpecBase.Direct {

  def verboseTree: String = """
object tpes
{
  trait I1
  trait I2
  trait I3
  trait I4
  trait I5
  trait I6
  trait I7
  trait I8
  trait I9
}
import tpes._

object Tree
{
  implicit def i8(implicit p: I9): I8 = ???
  implicit def i7(implicit p: I8): I7 = ???
  implicit def i6a(implicit p: I7): I6 = ???
  implicit def i6b(implicit p: I8): I6 = ???
  implicit def i5(implicit p: I6): I5 = ???
  implicit def i4(implicit p: I5): I4 = ???
  implicit def i3a(implicit p: I4): I3 = ???
  implicit def i3b(implicit p: I4): I3 = ???
  implicit def i2(implicit p: I3): I2 = ???
  implicit def i1a(implicit p: I2): I1 = ???
  implicit def i1b(implicit p: I6): I1 = ???
  implicitly[I1]
}
  """

  check(verboseTree, profile = "-Vimplicits-verbose-tree")

  check(verboseTree)
}


================================================
FILE: core/src/test/scala/splain/plugin/ErrorsCompatSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class ErrorsCompatSpec extends SpecBase.File {

  check("byname") {
    checkSuccess()
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/PluginSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class PluginSpec extends SpecBase.File {

  override def basicSetting: String = super.basicSetting + " -Vimplicits-verbose-tree"

  override lazy val predefCode: String =
    """
      |object types
      |{
      |  class ***[A, B]
      |  class >:<[A, B]
      |  class C
      |  trait D
      |}
      |import types._
      |""".stripMargin.trim

  check("implicit resolution chains", "chain") {
    checkError()
  }

  check("higher kind argument", "higherKindArg") {
    checkError()
  }

  check("bounds") {
    checkError()
  }

  check("lazy") {
    checkError()
  }

  // TODO: cleanup, breakinfix is gone
//  skip("linebreak long infix types", "break") {
//    checkErrorWithBreak()
//  }

//  check("deephole") {
//    checkError()
//  }

  // TODO: remove, already in TreeSpec
//  describe("tree printing") {
//    check("complete", file = "tree", extra = "-Vimplicits-verbose-tree") {
//      checkError()
//    }
//
//    skip("compact", "tree", extra = "-Vimplicits-verbose-tree -P:splain:compact") {
//      checkError(Some("errorCompact"))
//    }
//  }

  //  TODO: feature removed
//  skip("prefix stripping", "prefix", extra = "-P:splain:keepmodules:2") {
//    checkError()
//  }

  //  TODO: feature removed
//  skip("regex-rewrite", extra = "-P:splain:rewrite:\\.Level;0/5") {
//    checkError()
//  }

  // TODO: remove, already checked in BasicSpec
//  check("refined type diff", "refined") {
//    checkError()
//  }

//  check("disambiguate types", "disambiguate") {
//    checkError()
//  }

  // TODO: remove, already in TruncRefinedSpec
//  check("truncate refined type", "truncrefined", extra = "-Vimplicits-max-refined 10") {
//    checkError()
//  }

  // TODO: remove, already checked in BasicSpec
//  check("byname higher order", "byname-higher") {
//    checkError()
//  }

  // TODO: remove, already checked in BasicSpec
//  check("tuple1") {
//    checkError()
//  }

  // TODO: remove, already checked in BasicSpec
//  describe("single types ") {
//
//    check("single") {
//      checkError()
//    }
//
//    check("in function", "single-fn") {
//      checkError()
//    }
//
//    check("with free symbol", "single-free") {
//      checkError()
//    }
//  }

  check("not a member", file = "member") {
    checkError()
  }

  check("implicit annotation with control character(s)", "implicit-ctrl-char") {
    checkError()
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/ShapelessSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class ShapelessSpec extends SpecBase.File {

  override def basicSetting: String = super.basicSetting + " -Vimplicits-verbose-tree"

  override lazy val predefCode: String =
    """
      |object types
      |{
      |  class ***[A, B]
      |  class >:<[A, B]
      |  class C
      |  trait D
      |}
      |import types._
      |""".stripMargin.trim
  // in all error messages from toolbox, line number has to -8 to get the real line number

  check("shapeless Record", "record") {
    checkError()
  }

  check("witness value types", "witness-value") {
    checkError()
  }

  check("lazyImplicit") {
    checkError()
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/VImplicitDivergingSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class VImplicitDivergingSpec extends SpecBase.File {

  override def defaultExtraSetting: String = "-Vimplicits-verbose-tree -P:splain:Vimplicits-diverging"

  check("self") {
    checkError()
  }

  check("circular") {
    checkError()
  }

  check(
    "... with max depth",
    "circular",
    profile = s"${Settings.defaultExtra} -P:splain:Vimplicits-diverging-max-depth:5"
  ) {
    checkError()
  }

  check("circular-recoverable") {
    checkSuccess()
  }

  check(
    ".... with max depth",
    "circular",
    profile = s"${Settings.defaultExtra} -P:splain:Vimplicits-diverging-max-depth:5"
  ) {
    checkError()
  }

  check("diverging") {
    checkError()
  }

  check("... without verbose-tree", "diverging-compact", profile = "-P:splain:Vimplicits-diverging") {
    checkError()
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/VImplicitDivergingXSource3Spec.scala
================================================
package splain.plugin

class VImplicitDivergingXSource3Spec extends VImplicitDivergingSpec {

  override lazy val suiteCanonicalName: String = classOf[VImplicitDivergingSpec].getCanonicalName
}


================================================
FILE: core/src/test/scala/splain/plugin/VTypeDetailPositionSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class VTypeDetailPositionSpec extends SpecBase.Direct {

  final val diff =
    """
object Diff {
  class Example {

    type VV
  }

  val e1 = new Example {

    type VV <: Int
  }

  implicitly[e1.VV =:= String]
  val x: e1.VV = ??? : String
}
  """

  describe("#44") {

    check(diff, numberOfErrors = 2)

    check(diff, profile = "-P:splain:Vtype-detail:position", numberOfErrors = 2)
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/VTypeDetailReductionSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class VTypeDetailReductionSpec extends SpecBase.Direct {

  final val foundReqVsImplicit =
    """
object FoundReqVsImplicit
{
trait Vec[+T] {
  type Head = Option[T]
}

val vecInt = new Vec[Int] {}
implicitly[vecInt.Head =:= Option[String]]

val x: vecInt.Head = ??? : Option[String]
}
"""

  describe("#101") {

    check(foundReqVsImplicit, numberOfErrors = 2)

    check(foundReqVsImplicit, profile = "-P:splain:Vtype-detail:reduction", numberOfErrors = 2)
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/VTypeDetailSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class VTypeDetailSpec extends SpecBase.Direct {

  final val wrongContexts =
    """
    object Test {

      class A {
        class B
        def b: B = new B
      }

      class F[T]

      val a = new A
      type AA = a.type

      def wrongf(a: A)(implicit b: (F[a.type])): Unit = {}

      wrongf(new A)(new F[AA])
      wrongf(new A)
    }
    """

  final val reduceToInfix =
    """
    object Test {
      trait ::[A, B]

      type K = String :: Int :: Boolean
      implicitly[K]

      def v: K = "abc"
    }
    """

  describe("#113") {

    check(wrongContexts, profile = "-P:splain:Vtype-detail:1", numberOfErrors = 2)

    check(wrongContexts, profile = "-P:splain:Vtype-detail:2", numberOfErrors = 2)

    check(wrongContexts, profile = "-P:splain:Vtype-detail:3", numberOfErrors = 2)

    check(wrongContexts, profile = "-P:splain:Vtype-detail:4", numberOfErrors = 2)

    check(wrongContexts, profile = "-P:splain:Vtype-detail:5", numberOfErrors = 2)

    check(wrongContexts, profile = "-P:splain:Vtype-detail:6", numberOfErrors = 2)
  }

  describe("#119") {

    check(reduceToInfix, profile = "-P:splain:Vtype-detail:3", numberOfErrors = 2)

    check(reduceToInfix, profile = "-P:splain:Vtype-detail:4", numberOfErrors = 2)
  }

}


================================================
FILE: core/src/test/scala/splain/plugin/VTypeDiffsDetailSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class VTypeDiffsDetailSpec extends SpecBase.Direct {

  final val diff =
    """
    object Diff {
      def add2(x:Long,y:Long): Long = x + y

      def add[Long](x: List[Long], y: List[Long]): List[Long] =
        if (x.isEmpty || y.isEmpty) Nil
        else add2(x.head, y.head) :: add(x.tail, y.tail)
    }
    object DiffInEq {
      def add2[T](y: T)(
          implicit
          ev: T =:= Long
      ): Long = 1L + ev(y)

      def add[Long](x: List[Long]): List[Long] = {

        add2(x.head)
      }
    }
    object DiffInSubtype {
      def add2[T](y: T)(
          implicit
          ev: T <:< Long
      ): Long = 1L + ev(y)

      def add[Long](x: List[Long]): List[Long] = {

        add2(x.head)
      }
    }
"""

  describe("#112") {

    check(diff, numberOfErrors = 4, profile = "-P:splain:Vtype-diffs-detail:1")

    check(diff, numberOfErrors = 4, profile = "-P:splain:Vtype-diffs-detail:2")

    check(diff, numberOfErrors = 4, profile = "-P:splain:Vtype-diffs-detail:4")
  }
}


================================================
FILE: core/src/test/scala/splain/plugin/ZIOSpec.scala
================================================
package splain.plugin

import splain.SpecBase

class ZIOSpec extends SpecBase.File {

  check("zlayer") {
    // TODO: is it still incorrect?
    checkError()
  }
}


================================================
FILE: core/src/test/scala/splain/test/TryCompileSpec.scala
================================================
package splain.test

import splain.SpecBase

object TryCompileSpec {

  final val successExample = {
    """
    object Example
    """
  }

  final val parsingErrorExample = {
    """
    object Example {
    """
  }

  class L
  type R

  final val typingErrorExample =
    """
      import splain.test.TryCompileSpec._
      
      object FoundReq {
        def f(r: R): Int = ???
        f(new L)
      }
      """

  case class S1(i: Int)

  object S1 {

    implicit def default: S1 = S1(0)
  }

  case class S2(i: Int)

  object S2Import {

    implicit def default: S2 = S2(1)
  }
}

class TryCompileSpec extends SpecBase {

  import TryCompileSpec._

  lazy val useReflect = TryCompile.UseReflect("")
  lazy val useNSC = TryCompile.UseNSC("")
  lazy val static = TryCompile.Static()

  describe("success") {

    val groundTruth = {
      """
        |Success
        | ---
        |
        |""".stripMargin
    }

    it(classOf[TryCompile.UseReflect].getName) {
      useReflect(successExample).toString must_==
        groundTruth
    }

    it(classOf[TryCompile.UseNSC].getName) {
      useNSC(successExample).toString must_==
        groundTruth
    }

    it(classOf[TryCompile.Static[_]].getName) {
      static(successExample).toString must_==
        groundTruth
    }
  }

  describe("parsingError") {

    val groundTruth =
      """
        |ParsingError
        | ---
        |newSource1.scala:1: error: '}' expected but eof found.
        |object Example {
        |                ^
        |""".stripMargin

    it(classOf[TryCompile.UseReflect].getName) {
      useReflect(parsingErrorExample).toString must_==
        groundTruth
    }

    it(classOf[TryCompile.UseNSC].getName) {
      useNSC(parsingErrorExample).toString must_==
        groundTruth
    }

    it(classOf[TryCompile.Static[_]].getName) {
      static(parsingErrorExample).toString must_==
        groundTruth
    }
  }

  describe("typing error") {

    val groundTruth =
      """
        |TypingError
        | ---
        |newSource1.scala:5: error: type mismatch;
        | found   : splain.test.TryCompileSpec.L
        | required: splain.test.TryCompileSpec.R
        |        f(new L)
        |          ^
        |""".stripMargin

    it(classOf[TryCompile.UseReflect].getName) {
      useReflect(typingErrorExample).toString must_==
        groundTruth
    }

    it(classOf[TryCompile.UseNSC].getName) {
      useNSC(typingErrorExample).toString must_==
        groundTruth
    }

    it(classOf[TryCompile.Static[_]].getName) {
      static(typingErrorExample).toString must_==
        groundTruth
    }

    it("... invoke implicitly") {

      object Scope extends static.FromCodeMixin {

        val trial: TryCompile = typingErrorExample
      }

      Scope.trial.toString must_==
        groundTruth

    }
  }

  describe("runtime implicit search") {

    it("default scope") {
      val result = useReflect(
        """
          |implicitly[splain.test.TryCompileSpec.S1]
          |""".stripMargin
      )

      result match {
        case v: TryCompile.Success#Evaluable =>
          assert(v.issues.isEmpty)
          assert(v.get == S1(0))
        case v =>
          throw new AssertionError("Expected success\n" + v)
      }
    }

    it("imported scope") {

      val compiled = useReflect(
        """
          |import splain.test.TryCompileSpec.S2Import._
          |
          |implicitly[splain.test.TryCompileSpec.S2]
          |""".stripMargin
      )

      compiled match {
        case v: TryCompile.Success#Evaluable =>
          assert(v.issues.isEmpty)
          assert(v.get == S2(1))
        case v =>
          throw new AssertionError("Expected success\n" + v)
      }
    }
  }
}


================================================
FILE: core/src/testFixtures/scala/splain/TestHelpers.scala
================================================
package splain

import org.scalatest.exceptions.TestFailedException
import org.scalatest.{Assertion, Suite}
import org.slf4j.LoggerFactory
import splain.test.{Issue, TryCompile}

import java.nio.file.{FileSystems, Files, Path, Paths}
import java.util.concurrent.atomic.AtomicInteger
import scala.language.implicitConversions
import scala.util.Try

trait TestHelpers extends Suite {

  import TestHelpers._

  protected def basicSetting: String = "-Vimplicits -Vtype-diffs"

  protected def defaultExtraSetting: String = ""

  object Settings {

    final lazy val basic = basicSetting
    final lazy val defaultExtra: String = defaultExtraSetting
  }

  lazy val suiteCanonicalName: String = this.getClass.getCanonicalName

  final protected lazy val resourceDir: String = suiteCanonicalName.split('.').mkString("/")

  def resourcePath(name: String, fname: String): Path = FileSystems.getDefault.getPath(resourceDir, name, fname)

  def fileContentString(name: String, fname: String): String = {

    val path = resourcePath(name, fname)

    val resource = ClassLoader.getSystemClassLoader.getResource(path.toString)
    require(resource != null, s"Cannot find resource: $path")

    val actualPath = Paths.get(resource.toURI)

    new String(Files.readAllBytes(actualPath))
  }

  def groundTruth(name: String, fname: Option[String] = None): String =
    Try {
      fileContentString(name, fname.getOrElse("error")).stripLineEnd
    }.recover { _: Throwable =>
      fileContentString(name, fname.getOrElse("check")).stripLineEnd
    }.get

  lazy val predefCode = ""

  protected lazy val effectivePredef: String = {
    val trimmed = predefCode.trim
    if (trimmed.isEmpty) {
      trimmed
    } else {
      trimmed + "\n"
    }
  }

  def getEngine(settings: String): TryCompile.Engine = {
    //    TryCompile.UseReflect(settings)
    TryCompile.UseNSC(settings)
  }

  sealed trait Profile {

    def text: String
  }

  object Profile {

    case class Splain(extraSetting: String = Settings.defaultExtra) extends Profile {

      override lazy val text = s"$enableSplainPlugin $basicSetting $extraSetting"
    }

    case class BuiltIn(extraSetting: String = Settings.defaultExtra) extends Profile {

      override lazy val text = s"$basicSetting $extraSetting"
    } // use the compiler with option but no plugin

    case object Disabled extends Profile {

      override def text: String = ""
    } // just use the plain old compiler as-is

    implicit def fromString(v: String): Splain = Splain(v)

    lazy val default: Splain = Splain()
  }

  class TestCase(code: String, setting: Profile) {

    lazy val codeWithPredef: String = effectivePredef + code

    case class CompileWith(settings: String) {

      private lazy val engine = getEngine(settings)

      def compile(): TryCompile = engine(codeWithPredef)

      def compileError(): String =
        compile() match {
          case v: TryCompile.TypingError =>
            v.Error.displayIssues
          case TryCompile.OtherFailure(ee) =>
            throw new AssertionError(s"Cannot compile: $ee", ee)
          case ee @ _ =>
            throw new AssertionError(s"Type error not detected: $ee")
        }
    }

    def compileSuccess(): Option[String] =
      compileWith.compile() match {
        case _: TryCompile.Success =>
          None
        case v: TryCompile.Failure =>
          Some(v.Error.displayIssues)
      }

    def checkSuccess(): Assertion =
      assert(compileSuccess().isEmpty)

    lazy val compileWith: CompileWith = CompileWith(setting.text)
  }

  implicit class SpecStringOps(self: String) {

    def stripSpaceAtEnd(v: String): String = {

      v.reverse.dropWhile { v =>
        (v == ' ') || (v == '\r')
      }.reverse
    }

    def canonize(v: String): String = {
      v.split('\n').map(stripSpaceAtEnd).mkString("\n")
    }

    def must_==(groundTruth: String): Unit = {
      val left = canonize(self)
      val right = canonize(groundTruth)

      try {
        assert(left === right)
      } catch {
        case e: TestFailedException =>
          // augmenting

          val result =
            s"""
               |expected: <
               |${right}
               |> but was: <
               |${left}
               |>
            """.stripMargin.trim

          val ee = e.modifyMessage { _ =>
            Some(result)
          }

          throw ee
      }
      ()
    }
  }

  case class FileCase(name: String, profile: Profile = Profile.default)
      extends TestCase(fileContentString(name, "code.scala"), profile) {

    def checkError(errorFile: Option[String] = None): Unit = {

      compileWith.compileError() must_== groundTruth(name, errorFile)
    }
  }

  type CheckFile = FileCase => Unit

  def checkError(errorFile: Option[String] = None): CheckFile = { cc =>
    cc.compileWith.compileError() must_== groundTruth(cc.name, errorFile)
  }

  def checkErrorWithBreak(errorFile: Option[String] = None, length: Int = 20): CheckFile = { cc =>
    val withBreak = cc.copy(profile = s"-Vimplicits-breakinfix $length")
    withBreak.checkError(errorFile)
  }

  def checkSuccess(): CheckFile = { cc =>
    assert(cc.compileSuccess().isEmpty)
    ()
  }

  case class DirectCase(code: String, setting: Profile = Profile.default) extends TestCase(code, setting)

  case class DirectRunner() {

    case class ParseGroundTruths(
        startsWith: String = Issue.defaultSrcName,
        fName: Option[String] = None
    ) {

      lazy val raw: String = {

        val gt = groundTruth("__direct", fName)
        gt
      }

      lazy val cases: Seq[String] = {
        val regex = s"(^|\n)$startsWith"

        val result = raw
          .split(
            regex
          )
          .toSeq
          .filter(_.trim.nonEmpty)
          .map { line =>
            (startsWith + line).trim
          }

        result
      }
    }

    object DefaultGroundTruths extends ParseGroundTruths()

    lazy val groundTruths: Seq[String] = DefaultGroundTruths.cases

    val pointer = new AtomicInteger(0)
  }
}

object TestHelpers {

  lazy val userDir: String = System.getProperty("user.dir").stripSuffix("/")

  val plugin: String = Option(System.getProperty("splain.jar")).getOrElse {
    val dir = FileSystems.getDefault.getPath(userDir + "/build/libs")
    val file =
      Files
        .list(dir)
        .toArray
        .map(v => v.asInstanceOf[Path])
        .filter(v => v.toString.endsWith(".jar"))
        .sortBy(v => v.toString)
        .filterNot { v =>
          Seq("-javadoc.jar", "-sources.jar", "-test-fixtures.jar")
            .map { suffix =>
              v.toString.endsWith(suffix)
            }
            .exists(identity)
        }
        .head

    LoggerFactory
      .getLogger(this.getClass)
      .debug(
        s"Using plugin jar: ${file.toString}"
      )

    file.toAbsolutePath.toString
  }

  lazy val enableSplainPlugin: String = {

    val rows = s"""
                  |-Xplugin:$plugin
                  |""".stripMargin.trim

    rows.split('\n').mkString(" ")
  }

}


================================================
FILE: core/src/testFixtures/scala/splain/builtin/BasicFixture.scala
================================================
package splain.builtin

trait BasicFixture {

  // from scalac tests START HERE
  final val chain =
    """
object ImplicitChain
{
  trait I1
  trait I2
  trait I3
  trait I4
  trait II
  implicit def i1(implicit impPar7: I3): I1 = ???
  implicit def i2a(implicit impPar8: I3): I2 = ???
  implicit def i2b(implicit impPar8: I3): I2 = ???
  implicit def i4(implicit impPar9: I2): I4 = ???
  implicit def g(implicit impPar3: I1, impPar1: I4): II = ???
  implicitly[II]
}
  """

  final val foundReq =
    """
object FoundReq
{
  class L
  type R
  def f(r: R): Int = ???
  f(new L)
}
  """

  final val longArg =
    """
object Long {
  class VeryLong[T]

  implicitly[VeryLong[
    VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]
  ]]
}
"""

  final val longFoundReq =
    """
object Long {
  class VeryLong[T]
  class VeryLong2[T]

  type Found = VeryLong[
    VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]
  ]

  type Req = VeryLong[
    VeryLong[VeryLong2[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]
  ]

  val str: Req = ??? : Found
}
"""

  final val compoundDiff =
    """
object Compound {
  trait T
  type F[A] = A
  def x[A](y: A): F[A with T] = y.asInstanceOf[A with T]
  def f[A](a: A with String): F[A] = a
  val y: F[Int with T] = x(x(1))
  f(y)

  val z: Int with T = x(x(1))
  f(z)
}
    """

  final val LongRefined =
    """
object Long {
  class VeryLong[T]

  implicitly[VeryLong[
    VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]
  ] { type A = Int; type B = Int; type C = Int; type D = Int; type E = Int; type F = Int; type G = Int; type H = Int}]
}
    """

  final val LongTuple =
    """
object Long {
  class VeryLong[T]

  implicitly[
      (
          VeryLong[Int],
          VeryLong[
            VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[Int]]]]]]]
          ]
      )
  ]
}
  """

  final val foundReqLongTuple =
    """
object Long {
  class VeryLong[T]

  val x: (
      VeryLong[Int],
      VeryLong[
        VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[Int]]]]]]]
      ]
  ) = ???

  val y: (
      VeryLong[Int],
      VeryLong[
        VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[VeryLong[String]]]]]]]
      ]
  ) = x
}
"""

  final val foundReqSameSymbol =
    """
object FoundReqSameSymbol {

  trait T { type TT }
  trait A { val t: T }

  trait B {
    val a: A
    final val t = a.t

    val t1: a.t.TT = ???
    val t2: t.TT = t1
  }
}
  """

  final val bounds =
    """
object Bounds
{
  trait Base
  trait Arg
  trait F[A]
  implicit def g[A <: Base, B]: F[A] = ???
  implicitly[F[Arg]]
}
  """

  final val longAnnotationMessage =
    """
object Long
{
  def long(implicit ec: scala.concurrent.ExecutionContext): Unit = ???
  long
}
  """

  final val longInfix =
    """
object InfixBreak
{
  type ::::[A, B]
  trait VeryLongTypeName
  trait Short
  type T1 = VeryLongTypeName :::: VeryLongTypeName :::: VeryLongTypeName ::::
    VeryLongTypeName
  type T2 = T1 :::: (Short :::: Short) :::: T1 :::: T1
  implicit def f(implicit impPar4: List[T2]): String = ???
  implicitly[String]
}
  """

  final val deeplyNestedHole =
    """
object DeepHole
{
  trait C1[F[_]]
  trait C2[F[_], G[_], A]
  trait C3[A, B]
  trait C4[A]
  type Id[A] = A
  type T1[X] = C3[List[String], X]
  type T2[Y] = C2[Id, C4, Y]
  type T3[Z] = C2[T1, T2, Z]
  implicitly[C1[T3]]
}
  """

  final val auxType =
    """
object Aux
{
  trait C
  trait D
  trait F
  object F { type Aux[A, B] = F { type X = A; type Y = B } }
  implicit def f[A, B](implicit impPar10: C): F { type X = A; type Y = B } =
    ???
  implicitly[F.Aux[C, D]]
}
  """

  final val refined1 =
    """
object Refined
{
  trait A
  trait B
  trait C
  trait D
  trait E
  trait F
  def f(a: A with B with C { type Y = String; type X = String; type Z = String }): Unit = ???
  val x: B with E with A with F { type X = Int; type Y = String } = ???
  f(x)

  object Sub1 {
    trait A

    object Sub2 {
      trait B

      def f(a: A with B with C { type Y = String; type X = String; type Z = String }): Unit = ???
      val x: B with E with A with F { type X = Int; type Y = String } = ???
      f(x)
    }
  }
}
  """

  final val refined2 =
    """
object Refined
{
  trait Node {
    type T
  }

  type NodeLt[T0] = Node {type T <: T0}

  implicitly[NodeLt[Int]]

  val k: NodeLt[Int] = 1
}
    """

  final val refined3 =
    """
object Refined
{
  trait Node {
    type T
  }

  type NodeAux[T0] = Node { type T = T0 }
  type NodeLt[T0] = NodeAux[_ <: T0]

  implicitly[NodeLt[Int]]

  val k: NodeLt[Int] = 1
}
    """

  final val disambiguateQualified =
    """
object A
{
  object B
  {
    object X
    {
      object Y
      {
        type T
      }
    }
  }
  object C
  {
    object X
    {
      object Y
      {
        type T
      }
    }
  }
  def f(a: B.X.Y.T): Unit = ()
  val x: C.X.Y.T = ???
  f(x: C.X.Y.T)
}
  """

  final val bynameParam =
    """
object Foo
{
  type A
  type B
  def f(g: (=> A) => B): Unit = ()
  f(1: Int)
}
  """

  final val tuple1 =
    """
object Tup1
{
  val a: Tuple1[String] = "Tuple1": String
}
  """

  final val singleType =
    """
object SingleImp
{
  class ***[A, B]
  val a = 1
  val b = 2

  implicitly[a.type *** b.type]
}
  """

  final val singleTypeInFunction =
    """
object SingleImp
{
  class ***[A, B]
  def fn(): Unit = {
    val a = 1
    val b = 2

    implicitly[a.type *** b.type]
  }
}
  """

  final val singleTypeWithFreeSymbol =
    """
object SingleImp
{
  class ***[A, B]
  def fn[A, B](a: A, b: B) = {

    implicitly[a.type *** b.type]
  }
}
  """

  final val parameterAnnotation =
    """
  import scala.collection.mutable
  object Test {
    val o = new Object
    val ms = scala.collection.mutable.SortedSet(1,2,3)
    ms.map(_ => o)
  }
  """
  // from scalac tests END HERE

  final val shorthandTypes =
    """
object a {
  type TypeA
  object b {
    type TypeB
    object c {
      type TypeC
      object d {
        type TypeD
        implicitly[List[TypeA]]
        implicitly[Seq[TypeB]]
        implicitly[Traversable[TypeC]]
        implicitly[Iterator[TypeD]]
      }
    }
  }
}
"""

}


================================================
FILE: dev/.CI.sh
================================================
#!/usr/bin/env bash

CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"

echo "[COMPILING]" && \
"${CRDIR}"/test.sh "${@}"


================================================
FILE: dev/CI-latest.sh
================================================
#!/usr/bin/env bash

CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"

ARGS=${@}

exec "${CRDIR}"/.CI.sh ${ARGS}

================================================
FILE: dev/format-code.sh
================================================
#!/usr/bin/env bash

FWDIR="$(cd "`dirname "$0"`"/..; pwd)"

cd "${FWDIR}" || exit

"${FWDIR}"/gradlew clean scalafix -Dorg.gradle.parallel=false
 # consumes too much memory to run in parallel

scalafmt

================================================
FILE: dev/gradle-versions.sh
================================================
#!/usr/bin/env bash

FWDIR="$(
  cd "$(dirname "$0")"/.. || exit
  pwd
)"

${FWDIR}/gradlew wrapper --gradle-version=8.14.3

${FWDIR}/gradlew dependencyUpdates "$@"


================================================
FILE: dev/log-make-all.sh
================================================
#!/usr/bin/env bash

FWDIR="$(
  cd "$(dirname "$0")"/.. || exit
  pwd
)"
CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"
DATE=$(date --iso-8601=second)

mkdir -p ${FWDIR}/logs/compile

${CRDIR}/make-all.sh --info > ${FWDIR}/logs/compile/"$DATE".log


================================================
FILE: dev/make-all.sh
================================================
#!/usr/bin/env bash

FWDIR="$(
  cd "$(dirname "$0")"/.. || exit
  pwd
)"
DATE=$(date --iso-8601=second)

mkdir -p ${FWDIR}/logs
mkdir -p ${FWDIR}/logs/dependencyTree

${FWDIR}/gradlew -q dependencyTree "${@}" > ${FWDIR}/logs/dependencyTree/"$DATE".log

${FWDIR}/gradlew testClasses assemble "${@}"


================================================
FILE: dev/publish-all.sh
================================================
#!/usr/bin/env bash

CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"

for i in $(seq 9 18); do
    echo " [PUBLISHING] -PscalaVersion=2.13.$i"
    $CRDIR/publish.sh -PscalaVersion=2.13.$i
done

================================================
FILE: dev/publish.template.sh
================================================
#!/usr/bin/env bash

FWDIR="$(
  cd "$(dirname "$0")"/.. || exit
  pwd
)"

${FWDIR}/gradlew publishToSonatype \
  closeSonatypeStagingRepository \
  -PsonatypeApiUser=??? \
  -PsonatypeApiKey=??? \
  -Psigning.gnupg.secretKey=??? \
  -Psigning.gnupg.passphrase=??? \
  "${@}"


================================================
FILE: dev/publishM2-all.sh
================================================
#!/usr/bin/env bash

CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"

for i in $(seq 9 18); do
    echo " [PUBLISHING] -PscalaVersion=2.13.$i"
    $CRDIR/publishM2.sh -PscalaVersion=2.13.$i
done

================================================
FILE: dev/publishM2.sh
================================================
#!/usr/bin/env bash

CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"

echo "[COMPILING]" && \
  "${CRDIR}"/../gradlew clean && \
  "${CRDIR}"/make-all.sh publishToMavenLocal "${@}"


================================================
FILE: dev/test.sh
================================================
#!/usr/bin/env bash

FWDIR="$(
  cd "$(dirname "$0")"/.. || exit
  pwd
)"
CRDIR="$(
  cd "$(dirname "$0")" || exit
  pwd
)"

"${CRDIR}"/make-all.sh "${@}" && \
${FWDIR}/gradlew test "${@}"


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradle.properties
================================================

scalaGroup=org.scala-lang

scalaVersion=2.13.18

org.gradle.parallel=true
#org.gradle.caching=true

================================================
FILE: gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH="\\\"\\\""


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    if ! command -v java >/dev/null 2>&1
    then
        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC2039,SC3045
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC2039,SC3045
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi


# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command:
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
#     and any embedded shellness will be escaped.
#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
#     treated as '${Hostname}' itself on the command line.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
        "$@"

# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
    die "xargs is not available"
fi

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem

@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute

echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2

goto fail

:execute
@rem Setup the command line

set CLASSPATH=


@rem Execute Gradle
"%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" %*

:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: img/VtypeDetail.md
================================================
XXX.scala:15: error: type mismatch;

- Test.F\[

  - 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>)

    - <label class="ob-comment" title="" style="background:green"> ――(left side reduced from) <input type="checkbox"> <span style=""> reduction </span></label>

      - Test.AA  <label class="ob-comment" title="" style="background:blue"> (which expands to)  Test.a.type <input type="checkbox"> <span style=""> alias </span></label>

- \]

================================================
FILE: img/VtypeDiffsDetail.md
================================================
XXX.scala:16: error: implicit error;

- !I ev:

  - Long(<label class="ob-comment" title="" style="background:red"> in method add <input type="checkbox"> <span style=""> disambiguation </span></label>) =:= scala.Long

  - ――(<label class="ob-comment" title="" style="background:yellow"> comparing \<found\> =:= \<required\> <input type="checkbox"> <span style=""> builtIn </span></label>)

    - found   : Long(in method add)

    - required: scala.Long

  - Cannot prove that Long =:= Long.

================================================
FILE: settings.gradle.kts
================================================
//val versions = gradle.rootProject.versions()


include(
    ":core",
    ":testing:acceptance"
)


pluginManagement.repositories {
    gradlePluginPortal()
    mavenCentral()
    // maven("https://dl.bintray.com/kotlin/kotlin-dev")
}


================================================
FILE: testing/acceptance/build.gradle.kts
================================================
val vs: Versions = versions()

dependencies {

    testImplementation(project(":core"))
    testFixturesApi(testFixtures(project(":core")))

    scalaCompilerPlugins(project(":core"))

//    testImplementation("com.chuusai:shapeless_${vs.scalaBinaryV}:2.3.7")
//    testImplementation("dev.zio:zio_${vs.scalaBinaryV}:1.0.4")
}

tasks {

    withType<ScalaCompile> {

        scalaCompileOptions.apply {

            additionalParameters!!.addAll(
                listOf(
                    "-Vimplicits",
                    "-Vtype-diffs",
                    "-P:splain:Vimplicits-diverging"
                )
            )

//            println("===== SCALAC ARGS ======")
//            additionalParameters!!.forEach {
//                v ->
//                println(v)
//            }
        }
    }
}


================================================
FILE: testing/acceptance/src/test/resources/splain/builtin/BasicSpec/__direct/check
================================================
newSource1.scala:13: error: implicit error;
!I e: splain.acceptance.builtin.StaticBasicSpec.ImplicitChain.II
ImplicitChain.g invalid because
!I impPar3: ImplicitChain.I1
――ImplicitChain.i1 invalid because
  !I impPar7: ImplicitChain.I3
  implicitly[II]
            ^
newSource1.scala:6: error: type mismatch;
  found   : splain.acceptance.builtin.StaticBasicSpec.FoundReq.L
  ━━━━━━━━:
  required: splain.acceptance.builtin.StaticBasicSpec.FoundReq.R
  f(new L)
    ^
newSource1.scala:13: error: type mismatch;
  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
      found   : splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]
                        ]
                      ]
                    ]
                  ]
                ]
      ━━━━━━━━:
      required: splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong2[
                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]
                        ]
                      ]
                    ]
                  ]
                ]
    ]
  ]
  val str: Req = ??? : Found
                     ^
newSource1.scala:4: error: implicit error;
!I e:
  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]
              ]
            ]
          ]
        ]
      ]
    ]
  ]
  implicitly[VeryLong[
            ^
newSource1.scala:7: error: type mismatch;
  splain.acceptance.builtin.StaticBasicSpec.Compound.y.type┃String
  f(y)
    ^
newSource1.scala:4: error: implicit error;
!I e:
  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[String]
              ]
            ]
          ]
        ]
      ]
    ]
  ] {
    type A = Int;
    type B = Int;
    type C = Int;
    type D = Int;
    type E = Int;
    type F = Int;
    type G = Int;
    type H = Int
  }
  implicitly[VeryLong[
            ^
newSource1.scala:4: error: implicit error;
!I e:
  (
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int],
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int]
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  )
  implicitly[
            ^
newSource1.scala:16: error: type mismatch;
  (
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int],
    splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
      splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
        splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
          splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
            splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
              splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[
                  splain.acceptance.builtin.StaticBasicSpec.Long.VeryLong[Int┃String]
                ]
              ]
            ]
          ]
        ]
      ]
    ]
  )
  ) = x
      ^
newSource1.scala:11: error: type mismatch;
  B.this.t1.type┃B.this.t.TT
    val t2: t.TT = t1
                   ^
newSource1.scala:7: error: implicit error;
!I e:
  splain.acceptance.builtin.StaticBasicSpec.Bounds.F[
    splain.acceptance.builtin.StaticBasicSpec.Bounds.Arg
  ]
Bounds.g invalid because
nonconformant bounds;
[splain.acceptance.builtin.StaticBasicSpec.Bounds.Arg, Nothing]
[A <: Bounds.Base, B]
  implicitly[F[Arg]]
            ^
newSource1.scala:4: error: implicit error;
!I ec: scala.concurrent.ExecutionContext
  Cannot find an implicit ExecutionContext. You might add
  an (implicit ec: ExecutionContext) parameter to your method.

  The ExecutionContext is used to configure how and on which
  thread pools asynchronous tasks (such as Futures) will run,
  so the specific ExecutionContext that is selected is important.

  If your application does not define an ExecutionContext elsewhere,
  consider using Scala's global ExecutionContext by defining
  the following:

  implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global

  long
  ^
newSource1.scala:10: error: implicit error;
!I e: String
f invalid because
!I impPar4:
  List[
    (
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName
    )
    ::::
    (
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.Short ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.Short
    )
    ::::
    (
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
      splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName
    )
    ::::
    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName ::::
    splain.acceptance.builtin.StaticBasicSpec.InfixBreak.VeryLongTypeName
  ]
   (No implicit view available from Int => splain.acceptance.builtin.StaticBasicSpec.InfixBreak.T2.)

  implicitly[String]
            ^
newSource1.scala:11: error: implicit error;
!I e:
  splain.acceptance.builtin.StaticBasicSpec.DeepHole.C1[
    [Z]splain.acceptance.builtin.StaticBasicSpec.DeepHole.C2[splain.acceptance.builtin.StaticBasicSpec.DeepHole.T1,splain.acceptance.builtin.StaticBasicSpec.DeepHole.T2,Z]
  ]
  implicitly[C1[T3]]
            ^
newSource1.scala:9: error: implicit error;
!I e:
  splain.acceptance.builtin.StaticBasicSpec.Aux.F.Aux[
    splain.acceptance.builtin.StaticBasicSpec.Aux.C,
    splain.acceptance.builtin.StaticBasicSpec.Aux.D
  ]
Aux.f invalid because
!I impPar10: Aux.C
  implicitly[F.Aux[C, D]]
            ^
newSource1.scala:11: error: type mismatch;
  splain.acceptance.builtin.StaticBasicSpec.Refined.A with
  splain.acceptance.builtin.StaticBasicSpec.Refined.B with
  found   : splain.acceptance.builtin.StaticBasicSpec.Refined.E
  ━━━━━━━━:
  required: splain.acceptance.builtin.StaticBasicSpec.Refined.C with
  splain.acceptance.builtin.StaticBasicSpec.Refined.F┃<none> {
    type X = Int┃String;
    type Y = String;
    type Z = <none>┃String
  }
  f(x)
    ^
newSource1.scala:9: error: implicit error;
!I e: splain.acceptance.builtin.StaticBasicSpec.Refined.Node {type T <: Int}
  implicitly[NodeLt[Int]]
            ^
newSource1.scala:10: error: implicit error;
!I e: splain.acceptance.builtin.StaticBasicSpec.Refined.Node{type T = _$1} forSome { type _$1 <: Int }
  implicitly[NodeLt[Int]]
            ^
newSource1.scala:25: error: type mismatch;
  C.X.Y.T┃B.X.Y.T
  f(x: C.X.Y.T)
     ^
newSource1.scala:6: error: type mismatch;
  found   : Int
  ━━━━━━━━:
  required: (=> splain.acceptance.builtin.StaticBasicSpec.Foo.A) => splain.acceptance.builtin.StaticBasicSpec.Foo.B
  f(1: Int)
     ^
newSource1.scala:3: error: type mismatch;
  String┃Tuple1[String]
  val a: Tuple1[String] = "Tuple1": String
                                  ^
newSource1.scala:7: error: implicit error;
!I e:
  splain.acceptance.builtin.StaticBasicSpec.SingleImp.a.type ***
  splain.acceptance.builtin.StaticBasicSpec.SingleImp.b.type
  implicitly[a.type *** b.type]
            ^
newSource1.scala:8: error: implicit error;
!I e: a.type *** b.type
    implicitly[a.type *** b.type]
              ^
newSource1.scala:6: error: implicit error;
!I e: a.type *** b.type
    implicitly[a.type *** b.type]
              ^
newSource1.scala:5: error: implicit error;
!I ev: scala.math.Ordering[Object]
  No implicit Ordering[Object] found to build a SortedSet[Object]. You may want to upcast to a Set[Int] first by calling `unsorted`.

Ordering.ordered invalid because
!I asComparable: Object => Comparable[Any]
  No implicit view available from Object => Comparable[_ >: Object].

Ordering.comparatorToOrdering invalid because
!I cmp: java.util.Comparator[Object]
    ms.map(_ => o)
          ^
newSource1.scala:9: error: implicit error;
!I e: List[splain.acceptance.builtin.StaticBasicSpec.a.TypeA]
   (No implicit view available from Int => splain.acceptance.builtin.StaticBasicSpec.a.TypeA.)

        implicitly[List[TypeA]]
                  ^


================================================
FILE: testing/acceptance/src/test/scala/splain/acceptance/Acceptance.scala
============================================
Download .txt
gitextract_4lf27vw3/

├── .gitattribute
├── .github/
│   └── workflows/
│       └── main.yml
├── .gitignore
├── .scalafix.conf
├── .scalafmt.conf
├── .travis.yml
├── LICENSE
├── README.md
├── build.gradle.kts
├── buildSrc/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               ├── Versions.kt
│               └── init.kt
├── core/
│   ├── build.gradle.kts
│   └── src/
│       ├── main/
│       │   ├── resources/
│       │   │   └── scalac-plugin.xml
│       │   ├── scala/
│       │   │   └── splain/
│       │   │       ├── Messages.scala
│       │   │       ├── PluginSettings.scala
│       │   │       ├── SplainInternalError.scala
│       │   │       ├── format/
│       │   │       │   └── package.scala
│       │   │       └── test/
│       │   │           ├── AutoLift.scala
│       │   │           ├── CachingFrontEnd.scala
│       │   │           ├── Issue.scala
│       │   │           ├── TryCompile.scala
│       │   │           └── TryCompileMacros.scala
│       │   └── scala-2.13.7+/
│       │       └── latest/
│       │           └── splain/
│       │               ├── ImplicitsExtension.scala
│       │               ├── SplainAnalyzer.scala
│       │               ├── SplainAnalyzerShim.scala
│       │               ├── SplainFormattersExtension.scala
│       │               ├── SplainFormattingExtension.scala
│       │               ├── SplainPlugin.scala
│       │               ├── SplainPluginLike.scala
│       │               ├── TyperCompatViews.scala
│       │               └── package.scala
│       ├── test/
│       │   ├── resources/
│       │   │   └── splain/
│       │   │       ├── builtin/
│       │   │       │   ├── BasicSpec/
│       │   │       │   │   └── __direct/
│       │   │       │   │       └── check
│       │   │       │   ├── MaxRefinedSpec/
│       │   │       │   │   └── __direct/
│       │   │       │   │       └── check
│       │   │       │   └── VerboseTreeSpec/
│       │   │       │       └── __direct/
│       │   │       │           └── check
│       │   │       └── plugin/
│       │   │           ├── ErrorsCompatSpec/
│       │   │           │   └── byname/
│       │   │           │       └── code.scala
│       │   │           ├── PluginSpec/
│       │   │           │   ├── ambiguous/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── bounds/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── chain/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── higherKindArg/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── implicit-ctrl-char/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── lazy/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   └── member/
│       │   │           │       ├── code.scala
│       │   │           │       └── error
│       │   │           ├── ShapelessSpec/
│       │   │           │   ├── lazyImplicit/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── record/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   └── witness-value/
│       │   │           │       ├── code.scala
│       │   │           │       └── error
│       │   │           ├── VImplicitDivergingSpec/
│       │   │           │   ├── circular/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── circular-recoverable/
│       │   │           │   │   └── code.scala
│       │   │           │   ├── diverging/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   ├── diverging-compact/
│       │   │           │   │   ├── code.scala
│       │   │           │   │   └── error
│       │   │           │   └── self/
│       │   │           │       ├── code.scala
│       │   │           │       └── error
│       │   │           ├── VTypeDetailPositionSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           ├── VTypeDetailReductionSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           ├── VTypeDetailSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           ├── VTypeDiffsDetailSpec/
│       │   │           │   └── __direct/
│       │   │           │       └── check
│       │   │           └── ZIOSpec/
│       │   │               └── zlayer/
│       │   │                   ├── code.scala
│       │   │                   └── error
│       │   └── scala/
│       │       └── splain/
│       │           ├── PlainPrettifier.scala
│       │           ├── ScalacticSpike.scala
│       │           ├── SpecBase.scala
│       │           ├── builtin/
│       │           │   ├── BasicSpec.scala
│       │           │   ├── BasicXSource3Spec.scala
│       │           │   ├── MaxRefinedSpec.scala
│       │           │   └── VerboseTreeSpec.scala
│       │           ├── plugin/
│       │           │   ├── ErrorsCompatSpec.scala
│       │           │   ├── PluginSpec.scala
│       │           │   ├── ShapelessSpec.scala
│       │           │   ├── VImplicitDivergingSpec.scala
│       │           │   ├── VImplicitDivergingXSource3Spec.scala
│       │           │   ├── VTypeDetailPositionSpec.scala
│       │           │   ├── VTypeDetailReductionSpec.scala
│       │           │   ├── VTypeDetailSpec.scala
│       │           │   ├── VTypeDiffsDetailSpec.scala
│       │           │   └── ZIOSpec.scala
│       │           └── test/
│       │               └── TryCompileSpec.scala
│       └── testFixtures/
│           └── scala/
│               └── splain/
│                   ├── TestHelpers.scala
│                   └── builtin/
│                       └── BasicFixture.scala
├── dev/
│   ├── .CI.sh
│   ├── CI-latest.sh
│   ├── format-code.sh
│   ├── gradle-versions.sh
│   ├── log-make-all.sh
│   ├── make-all.sh
│   ├── publish-all.sh
│   ├── publish.template.sh
│   ├── publishM2-all.sh
│   ├── publishM2.sh
│   └── test.sh
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── img/
│   ├── VtypeDetail.md
│   └── VtypeDiffsDetail.md
├── settings.gradle.kts
└── testing/
    └── acceptance/
        ├── build.gradle.kts
        └── src/
            └── test/
                ├── resources/
                │   └── splain/
                │       └── builtin/
                │           └── BasicSpec/
                │               └── __direct/
                │                   └── check
                └── scala/
                    └── splain/
                        └── acceptance/
                            ├── Acceptance.scala
                            └── builtin/
                                └── StaticBasicSpec.scala
Condensed preview — 114 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (203K chars).
[
  {
    "path": ".gitattribute",
    "chars": 181,
    "preview": "*.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 te"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 2097,
    "preview": "name: CI\n\non: [push]\n\njobs:\n\n  vars:\n    runs-on: ubuntu-latest\n\n    outputs:\n      experimentalScalaVersions: \"\"\n\n    s"
  },
  {
    "path": ".gitignore",
    "chars": 551,
    "preview": "*.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/*\n"
  },
  {
    "path": ".scalafix.conf",
    "chars": 575,
    "preview": "runner.dialect = scala213\n\n// Built in rules\nrules = [\n  NoAutoTupling\t// Rewrite that inserts explicit tuples for adapt"
  },
  {
    "path": ".scalafmt.conf",
    "chars": 789,
    "preview": "version = \"3.7.14\"\nrunner.dialect = scala213\n\nmaxColumn = 120\nlineEndings = unix\n\n# Only format files tracked by git.\npr"
  },
  {
    "path": ".travis.yml",
    "chars": 60,
    "preview": "jdk:\n  - openjdk8\nlanguage: scala\nscript: 'sbt splain/test'\n"
  },
  {
    "path": "LICENSE",
    "chars": 1082,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Torsten Schmits\n\nPermission is hereby granted, free of charge, to any person o"
  },
  {
    "path": "README.md",
    "chars": 19588,
    "preview": "# A scala compiler plugin for more concise errors\n\nThis plugin removes some of the redundancy of the compiler output and"
  },
  {
    "path": "build.gradle.kts",
    "chars": 10774,
    "preview": "import org.gradle.util.internal.VersionNumber\n\nimport com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask\n"
  },
  {
    "path": "buildSrc/build.gradle.kts",
    "chars": 153,
    "preview": "plugins {\n    `kotlin-dsl`\n}\n\nrepositories {\n    mavenLocal()\n    mavenCentral()\n//    jcenter()\n    maven(\"https://dl.b"
  },
  {
    "path": "buildSrc/src/main/kotlin/Versions.kt",
    "chars": 1014,
    "preview": "import org.gradle.api.Project\n\nclass Versions(private val project: Project) {\n\n    // TODO : how to group them?\n    val "
  },
  {
    "path": "buildSrc/src/main/kotlin/init.kt",
    "chars": 204,
    "preview": "import org.gradle.api.Project\n\n/**\n * Configures the current project as a Kotlin project by adding the Kotlin `stdlib` a"
  },
  {
    "path": "core/build.gradle.kts",
    "chars": 554,
    "preview": "val vs: Versions = versions()\n\ndependencies {\n\n    // see https://github.com/gradle/gradle/issues/13067\n    fun bothImpl"
  },
  {
    "path": "core/src/main/resources/scalac-plugin.xml",
    "chars": 90,
    "preview": "<plugin>\n    <name>splain</name>\n    <classname>splain.SplainPlugin</classname>\n</plugin>\n"
  },
  {
    "path": "core/src/main/scala/splain/Messages.scala",
    "chars": 257,
    "preview": "package splain\n\nobject Messages {\n  val hasMatching = \"hasMatchingSymbol reported error: \"\n\n  val typingTypeApply = \"typ"
  },
  {
    "path": "core/src/main/scala/splain/PluginSettings.scala",
    "chars": 3835,
    "preview": "package splain\n\nimport splain.PluginSettings.Keys.Key\n\nimport scala.collection.mutable\nimport scala.reflect.NameTransfor"
  },
  {
    "path": "core/src/main/scala/splain/SplainInternalError.scala",
    "chars": 305,
    "preview": "package splain\n\nclass SplainInternalError(detail: String, cause: Throwable = null)\n    extends InternalError(\n      \"You"
  },
  {
    "path": "core/src/main/scala/splain/format/package.scala",
    "chars": 129,
    "preview": "package splain\n\npackage object format {\n\n  // TODO: this entire package could be gone, already taken over by scalac form"
  },
  {
    "path": "core/src/main/scala/splain/test/AutoLift.scala",
    "chars": 1977,
    "preview": "package splain.test\n\nimport java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream}"
  },
  {
    "path": "core/src/main/scala/splain/test/CachingFrontEnd.scala",
    "chars": 586,
    "preview": "package splain.test\n\nimport scala.collection.mutable.ArrayBuffer\nimport scala.tools.reflect.FrontEnd\n\n// mimic of StoreR"
  },
  {
    "path": "core/src/main/scala/splain/test/Issue.scala",
    "chars": 1375,
    "preview": "package splain.test\n\nimport scala.collection.immutable.ArraySeq\nimport scala.reflect.internal.util.{BatchSourceFile, NoP"
  },
  {
    "path": "core/src/main/scala/splain/test/TryCompile.scala",
    "chars": 4350,
    "preview": "package splain.test\n\nimport scala.language.experimental.macros\nimport scala.language.implicitConversions\nimport scala.re"
  },
  {
    "path": "core/src/main/scala/splain/test/TryCompileMacros.scala",
    "chars": 3007,
    "preview": "package splain.test\n\nimport splain.test.AutoLift.SerializingLift\n\nimport scala.collection.mutable.ArrayBuffer\nimport sca"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/ImplicitsExtension.scala",
    "chars": 3302,
    "preview": "package splain\n\nimport scala.collection.concurrent.TrieMap\nimport scala.collection.mutable\nimport scala.tools.nsc.typech"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainAnalyzer.scala",
    "chars": 969,
    "preview": "package splain\n\nimport scala.collection.mutable\nimport scala.tools.nsc._\n\nclass SplainAnalyzer(val global: Global, val p"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainAnalyzerShim.scala",
    "chars": 383,
    "preview": "package splain\n\nimport scala.tools.nsc.typechecker.Analyzer\n\ntrait SplainAnalyzerShim {\n  self: SplainAnalyzer =>\n\n  def"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainFormattersExtension.scala",
    "chars": 7548,
    "preview": "package splain\n\nimport scala.tools.nsc.typechecker.splain._\n\nobject SplainFormattersExtension {}\n\ntrait SplainFormatters"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainFormattingExtension.scala",
    "chars": 24137,
    "preview": "package splain\n\nimport scala.annotation.tailrec\nimport scala.collection.concurrent.TrieMap\nimport scala.collection.mutab"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainPlugin.scala",
    "chars": 2318,
    "preview": "package splain\n\nimport scala.tools.nsc._\nimport scala.tools.nsc.typechecker.{Analyzer, MacroAnnotationNamers}\n\nclass Spl"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/SplainPluginLike.scala",
    "chars": 385,
    "preview": "package splain\n\nimport scala.collection.mutable\nimport scala.tools.nsc._\nimport scala.tools.nsc.plugins.PluginComponent\n"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/TyperCompatViews.scala",
    "chars": 4628,
    "preview": "package splain\n\nimport scala.reflect.internal.util.{NoSourceFile, Position}\n\ntrait TyperCompatViews {\n  self: SplainAnal"
  },
  {
    "path": "core/src/main/scala-2.13.7+/latest/splain/package.scala",
    "chars": 190,
    "preview": "import scala.tools.nsc.typechecker.splain.SimpleName\nimport scala.language.implicitConversions\n\npackage object splain {\n"
  },
  {
    "path": "core/src/test/resources/splain/builtin/BasicSpec/__direct/check",
    "chars": 7063,
    "preview": "newSource1.scala:13: error: implicit error;\n!I e: ImplicitChain.II\nImplicitChain.g invalid because\n!I impPar3: ImplicitC"
  },
  {
    "path": "core/src/test/resources/splain/builtin/MaxRefinedSpec/__direct/check",
    "chars": 304,
    "preview": "newSource1.scala:7: error: type mismatch;\n  TruncRefined.D┃TruncRefined.C {\n    type X = TruncRefined.C;\n    type Y = Tr"
  },
  {
    "path": "core/src/test/resources/splain/builtin/VerboseTreeSpec/__direct/check",
    "chars": 2011,
    "preview": "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:"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ErrorsCompatSpec/byname/code.scala",
    "chars": 126,
    "preview": "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"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/ambiguous/code.scala",
    "chars": 145,
    "preview": "object Ambiguous {\n  implicit val c1: C = ???\n  implicit val c2: C = ???\n  implicit def f1: D = ???\n  implicit def f2: D"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/ambiguous/error",
    "chars": 159,
    "preview": "ambiguous implicit values:\n both method f1 in object Ambiguous of type types.D\n and method f2 in object Ambiguous of typ"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/bounds/code.scala",
    "chars": 109,
    "preview": "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",
    "chars": 240,
    "preview": "newSource1.scala:12: error: implicit error;\n!I e: NonconformantBounds.F[types.D *** types.C]\nNonconformantBounds.f inval"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/chain/code.scala",
    "chars": 1351,
    "preview": "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[_]"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/chain/error",
    "chars": 768,
    "preview": "newSource1.scala:77: error: implicit error;\n!I e:\n  (types.C *** types.D) >:<\n  types.C with types.D {type A = types.D; "
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/higherKindArg/code.scala",
    "chars": 140,
    "preview": "import shapeless.Poly1\n\nobject pol extends Poly1\n\nobject Functors {\n\n  trait F[X[_]]\n\n  implicitly[F[({ type λ[X] = Eith"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/higherKindArg/error",
    "chars": 155,
    "preview": "newSource1.scala:17: error: implicit error;\n!I e: Functors.F[[X]scala.util.Either[Int,X]]\n  implicitly[F[({ type λ[X] = "
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/implicit-ctrl-char/code.scala",
    "chars": 229,
    "preview": "import annotation.implicitNotFound\n\nobject Annotation {\n\n  trait Arg\n\n  @implicitNotFound(\"A\\n   ┃ B\\n  ┃ C\")\n  trait F["
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/implicit-ctrl-char/error",
    "chars": 200,
    "preview": "newSource1.scala:25: error: implicit error;\n!I e: Annotation.G[Annotation.Arg]\nAnnotation.f invalid because\n!I ev: Annot"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/lazy/code.scala",
    "chars": 280,
    "preview": "import shapeless._\nimport shapeless.ops.hlist._\n\nobject LazyImp {\n  implicit def dc(\n      implicit\n      a: C *** D\n  )"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/lazy/error",
    "chars": 290,
    "preview": "newSource1.scala:25: error: implicit error;\n!I e: types.C\nc invalid because\n!I a: shapeless.Lazy[types.D]\n  could not fi"
  },
  {
    "path": "core/src/test/resources/splain/plugin/PluginSpec/member/code.scala",
    "chars": 67,
    "preview": "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",
    "chars": 116,
    "preview": "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",
    "chars": 228,
    "preview": "import shapeless.Lazy\n\nobject DivergingImplicits {\n\n  type C\n  type D\n\n  object Diverging {\n\n    trait ::[A, B]\n\n    imp"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/lazyImplicit/error",
    "chars": 238,
    "preview": "newSource1.scala:25: error: implicit error;\n!I e: DivergingImplicits.C :: DivergingImplicits.D\nDiverging.f invalid becau"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/record/code.scala",
    "chars": 353,
    "preview": "import shapeless._\nimport shapeless.record._\nimport shapeless.syntax.singleton._\n\nobject ShapelessRecord {\n  object Key\n"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/record/error",
    "chars": 190,
    "preview": "newSource1.scala:26: error: type mismatch;\n  ('sym ->> String) ::\n  (\"str\" ->> ShapelessRecord.Value.type) ::\n  (Shapele"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/witness-value/code.scala",
    "chars": 184,
    "preview": "import shapeless._\nimport shapeless.ops.hlist._\n\nobject WitnessImp {\n  def fn[A, B](a: A, b: B)(\n      implicit\n      ev"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ShapelessSpec/witness-value/error",
    "chars": 115,
    "preview": "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",
    "chars": 224,
    "preview": "object DivergingImplicits {\n\n  type C\n  type D\n\n  object Circular {\n    implicit def f(\n        implicit\n        c: C\n  "
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular/error",
    "chars": 461,
    "preview": "newSource1.scala:17: error: implicit error;\n!I e: DivergingImplicits.C\ng invalid because\n!I d: DivergingImplicits.D\ndive"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/circular-recoverable/code.scala",
    "chars": 295,
    "preview": "object DivergingImplicits {\n\n  type C\n  type D\n\n  trait LowLevel {\n\n    implicit def f2: D = ???\n  }\n\n  object Circular "
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging/code.scala",
    "chars": 269,
    "preview": "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     "
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging/error",
    "chars": 730,
    "preview": "newSource1.scala:16: error: implicit error;\n!I e: DivergingImplicits.C :: DivergingImplicits.D\nDiverging.f invalid becau"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging-compact/code.scala",
    "chars": 269,
    "preview": "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     "
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/diverging-compact/error",
    "chars": 480,
    "preview": "newSource1.scala:16: error: implicit error;\n!I e: DivergingImplicits.C :: DivergingImplicits.D\nDiverging.f invalid becau"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/self/code.scala",
    "chars": 154,
    "preview": "object DivergingImplicits {\n\n  type C\n  type D\n\n  object Endo {\n    implicit def f(\n        implicit\n        c: C\n    ):"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VImplicitDivergingSpec/self/error",
    "chars": 396,
    "preview": "newSource1.scala:12: error: implicit error;\n!I e: DivergingImplicits.C\nf invalid because\n!I c: DivergingImplicits.C\ndive"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDetailPositionSpec/__direct/check",
    "chars": 624,
    "preview": "newSource1.scala:12: error: implicit error;\n!I e: Diff.e1.VV =:= String\n  Cannot prove that Diff.e1.VV =:= String.\n\n  im"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDetailReductionSpec/__direct/check",
    "chars": 798,
    "preview": "newSource1.scala:8: error: implicit error;\n!I e: Option[Int] =:= Option[String]\n  Cannot prove that FoundReqVsImplicit.v"
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDetailSpec/__direct/check",
    "chars": 3315,
    "preview": "\nnewSource1.scala:15: error: type mismatch;\n  Test.F[Test.a.type┃a.type]\n      wrongf(new A)(new F[AA])\n                "
  },
  {
    "path": "core/src/test/resources/splain/plugin/VTypeDiffsDetailSpec/__direct/check",
    "chars": 2459,
    "preview": "newSource1.scala:6: error: type mismatch;\n  Long┃Long\n        else add2(x.head, y.head) :: add(x.tail, y.tail)\n         "
  },
  {
    "path": "core/src/test/resources/splain/plugin/ZIOSpec/zlayer/code.scala",
    "chars": 473,
    "preview": "import zio._\n\nobject layers {\n\n  trait Service1\n  trait Service2\n  trait Service3\n  trait Service4\n\n  val service1 = ZLa"
  },
  {
    "path": "core/src/test/resources/splain/plugin/ZIOSpec/zlayer/error",
    "chars": 300,
    "preview": "newSource1.scala:19: error: type mismatch;\n  zio.ZLayer[\n    Any,\n    Nothing,\n    <none>┃zio.Has[layers.Service4] with\n"
  },
  {
    "path": "core/src/test/scala/splain/PlainPrettifier.scala",
    "chars": 312,
    "preview": "//package splain\n//\n//import org.scalactic.{Prettifier, PrettyPair}\n//\n//object PlainPrettifier extends Prettifier {\n//\n"
  },
  {
    "path": "core/src/test/scala/splain/ScalacticSpike.scala",
    "chars": 1074,
    "preview": "//package splain\n//\n//import org.scalatest.Ignore\n//\n//@Ignore\n//class ScalacticSpike extends SpecBase {\n//\n//  it(\"can "
  },
  {
    "path": "core/src/test/scala/splain/SpecBase.scala",
    "chars": 3013,
    "preview": "package splain\n\nimport org.scalatest.funspec.AnyFunSpec\nimport org.slf4j.LoggerFactory\n\nimport scala.util.Try\n\ntrait Spe"
  },
  {
    "path": "core/src/test/scala/splain/builtin/BasicSpec.scala",
    "chars": 880,
    "preview": "package splain.builtin\n\nimport splain.SpecBase\n\nclass BasicSpec extends SpecBase.Direct with BasicFixture {\n\n  check(cha"
  },
  {
    "path": "core/src/test/scala/splain/builtin/BasicXSource3Spec.scala",
    "chars": 215,
    "preview": "package splain.builtin\n\nclass BasicXSource3Spec extends BasicSpec {\n\n  override lazy val suiteCanonicalName: String = cl"
  },
  {
    "path": "core/src/test/scala/splain/builtin/MaxRefinedSpec.scala",
    "chars": 380,
    "preview": "package splain.builtin\n\nimport splain.SpecBase\n\nclass MaxRefinedSpec extends SpecBase.Direct {\n\n  def truncrefined: Stri"
  },
  {
    "path": "core/src/test/scala/splain/builtin/VerboseTreeSpec.scala",
    "chars": 872,
    "preview": "package splain.builtin\n\nimport splain.SpecBase\n\nclass VerboseTreeSpec extends SpecBase.Direct {\n\n  def verboseTree: Stri"
  },
  {
    "path": "core/src/test/scala/splain/plugin/ErrorsCompatSpec.scala",
    "chars": 140,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass ErrorsCompatSpec extends SpecBase.File {\n\n  check(\"byname\") {\n    c"
  },
  {
    "path": "core/src/test/scala/splain/plugin/PluginSpec.scala",
    "chars": 2422,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass PluginSpec extends SpecBase.File {\n\n  override def basicSetting: St"
  },
  {
    "path": "core/src/test/scala/splain/plugin/ShapelessSpec.scala",
    "chars": 676,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass ShapelessSpec extends SpecBase.File {\n\n  override def basicSetting:"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VImplicitDivergingSpec.scala",
    "chars": 847,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VImplicitDivergingSpec extends SpecBase.File {\n\n  override def defa"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VImplicitDivergingXSource3Spec.scala",
    "chars": 194,
    "preview": "package splain.plugin\n\nclass VImplicitDivergingXSource3Spec extends VImplicitDivergingSpec {\n\n  override lazy val suiteC"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDetailPositionSpec.scala",
    "chars": 446,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDetailPositionSpec extends SpecBase.Direct {\n\n  final val diff"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDetailReductionSpec.scala",
    "chars": 514,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDetailReductionSpec extends SpecBase.Direct {\n\n  final val fou"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDetailSpec.scala",
    "chars": 1306,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDetailSpec extends SpecBase.Direct {\n\n  final val wrongContext"
  },
  {
    "path": "core/src/test/scala/splain/plugin/VTypeDiffsDetailSpec.scala",
    "chars": 1050,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass VTypeDiffsDetailSpec extends SpecBase.Direct {\n\n  final val diff =\n"
  },
  {
    "path": "core/src/test/scala/splain/plugin/ZIOSpec.scala",
    "chars": 165,
    "preview": "package splain.plugin\n\nimport splain.SpecBase\n\nclass ZIOSpec extends SpecBase.File {\n\n  check(\"zlayer\") {\n    // TODO: i"
  },
  {
    "path": "core/src/test/scala/splain/test/TryCompileSpec.scala",
    "chars": 3726,
    "preview": "package splain.test\n\nimport splain.SpecBase\n\nobject TryCompileSpec {\n\n  final val successExample = {\n    \"\"\"\n    object "
  },
  {
    "path": "core/src/testFixtures/scala/splain/TestHelpers.scala",
    "chars": 7063,
    "preview": "package splain\n\nimport org.scalatest.exceptions.TestFailedException\nimport org.scalatest.{Assertion, Suite}\nimport org.s"
  },
  {
    "path": "core/src/testFixtures/scala/splain/builtin/BasicFixture.scala",
    "chars": 6233,
    "preview": "package splain.builtin\n\ntrait BasicFixture {\n\n  // from scalac tests START HERE\n  final val chain =\n    \"\"\"\nobject Impli"
  },
  {
    "path": "dev/.CI.sh",
    "chars": 122,
    "preview": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\necho \"[COMPILING]\" && \\\n\"${CRDIR}\"/test.sh \"${@}"
  },
  {
    "path": "dev/CI-latest.sh",
    "chars": 113,
    "preview": "#!/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",
    "chars": 202,
    "preview": "#!/usr/bin/env bash\n\nFWDIR=\"$(cd \"`dirname \"$0\"`\"/..; pwd)\"\n\ncd \"${FWDIR}\" || exit\n\n\"${FWDIR}\"/gradlew clean scalafix -D"
  },
  {
    "path": "dev/gradle-versions.sh",
    "chars": 165,
    "preview": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\n\n${FWDIR}/gradlew wrapper --gradle-version=8.1"
  },
  {
    "path": "dev/log-make-all.sh",
    "chars": 252,
    "preview": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd"
  },
  {
    "path": "dev/make-all.sh",
    "chars": 299,
    "preview": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\nDATE=$(date --iso-8601=second)\n\nmkdir -p ${FWD"
  },
  {
    "path": "dev/publish-all.sh",
    "chars": 194,
    "preview": "#!/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]"
  },
  {
    "path": "dev/publish.template.sh",
    "chars": 276,
    "preview": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\n\n${FWDIR}/gradlew publishToSonatype \\\n  closeS"
  },
  {
    "path": "dev/publishM2-all.sh",
    "chars": 196,
    "preview": "#!/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]"
  },
  {
    "path": "dev/publishM2.sh",
    "chars": 183,
    "preview": "#!/usr/bin/env bash\n\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd\n)\"\n\necho \"[COMPILING]\" && \\\n  \"${CRDIR}\"/../gradlew "
  },
  {
    "path": "dev/test.sh",
    "chars": 189,
    "preview": "#!/usr/bin/env bash\n\nFWDIR=\"$(\n  cd \"$(dirname \"$0\")\"/.. || exit\n  pwd\n)\"\nCRDIR=\"$(\n  cd \"$(dirname \"$0\")\" || exit\n  pwd"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 253,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 99,
    "preview": "\nscalaGroup=org.scala-lang\n\nscalaVersion=2.13.18\n\norg.gradle.parallel=true\n#org.gradle.caching=true"
  },
  {
    "path": "gradlew",
    "chars": 8710,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "gradlew.bat",
    "chars": 2843,
    "preview": "@rem\n@rem Copyright 2015 the original author or authors.\n@rem\n@rem Licensed under the Apache License, Version 2.0 (the \""
  },
  {
    "path": "img/VtypeDetail.md",
    "chars": 903,
    "preview": "XXX.scala:15: error: type mismatch;\n\n- Test.F\\[\n\n  - Test.a.type (<label class=\"ob-comment\" title=\"\" style=\"background:r"
  },
  {
    "path": "img/VtypeDiffsDetail.md",
    "chars": 491,
    "preview": "XXX.scala:16: error: implicit error;\n\n- !I ev:\n\n  - Long(<label class=\"ob-comment\" title=\"\" style=\"background:red\"> in m"
  },
  {
    "path": "settings.gradle.kts",
    "chars": 236,
    "preview": "//val versions = gradle.rootProject.versions()\n\n\ninclude(\n    \":core\",\n    \":testing:acceptance\"\n)\n\n\npluginManagement.re"
  },
  {
    "path": "testing/acceptance/build.gradle.kts",
    "chars": 811,
    "preview": "val vs: Versions = versions()\n\ndependencies {\n\n    testImplementation(project(\":core\"))\n    testFixturesApi(testFixtures"
  },
  {
    "path": "testing/acceptance/src/test/resources/splain/builtin/BasicSpec/__direct/check",
    "chars": 10602,
    "preview": "newSource1.scala:13: error: implicit error;\n!I e: splain.acceptance.builtin.StaticBasicSpec.ImplicitChain.II\nImplicitCha"
  },
  {
    "path": "testing/acceptance/src/test/scala/splain/acceptance/Acceptance.scala",
    "chars": 676,
    "preview": "package splain.acceptance\n\nimport org.scalatest.funspec.AnyFunSpec\nimport splain.TestHelpers\nimport splain.test.TryCompi"
  },
  {
    "path": "testing/acceptance/src/test/scala/splain/acceptance/builtin/StaticBasicSpec.scala",
    "chars": 1113,
    "preview": "package splain.acceptance.builtin\n\nimport splain.acceptance.Acceptance\nimport splain.builtin.BasicFixture\n\nobject Static"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the tek/splain GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 114 files (179.8 KB), approximately 52.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!