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 | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.1.0 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.1.0-RC0 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.0.3 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.0.2 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.0.1 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.0.0 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.0.0-RC2 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v1.0.0-RC1 <br> (current) | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
| v0.x <br> (maintenance) - latest | [](https://github.com/tek/splain/actions/workflows/main.yml) |  |
# 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:

special consideration for `shapeless.Record`:

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:

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:

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`)

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`)

# 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
============================================
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.