Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scala 3 support #466

Merged
merged 42 commits into from
May 9, 2021
Merged

Scala 3 support #466

merged 42 commits into from
May 9, 2021

Conversation

keynmol
Copy link
Collaborator

@keynmol keynmol commented Mar 21, 2021

After lots of printlns I realised there was a custom scalameta-like parser for Scala 3.

All of the positions in sections had Input.None, so slicing wasn't working - making all tests fail.

I've added a few things on top of #443 (didn't realise it was in a fork), and now I seem to be getting

[error] Failed: Total 170, Failed 54, Errors 0, Passed 107, Skipped 9

On the 3.0.0-M3 tests. Some of them are super easy to fix (different wording error messages in Scala3), I'll take a look at the rest which might be more complex.

olafurpg and others added 3 commits January 6, 2021 11:48
Makes it easier to work in the build.
Previously, mdoc didn't support Scala 3 when processing markdown files,
it only supports Scala 3 worksheets. This commit adds support to
additionally process markdown files with Scala 3.

This is still a work-in-progress. Scala 2 tests are still passing and
the Scala 3 build *compiles* but tests fail.
@tgodzik
Copy link
Contributor

tgodzik commented Mar 22, 2021

After lots of printlns I realised there was a custom scalameta-like parser for Scala 3.

All of the positions in sections had Input.None, so slicing wasn't working - making all tests fail.

The positions coming from Scala 3 parser are empty. We used it before Scala 3 dialect for scalameta parser was finished. Do let me know if you need any help with Scala 3 part, that was mostly done by be 😅

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 25, 2021

Thanks @tgodzik I sort of took a stab at it almost mechanically, now it's the hard part.

I still need to figure out @olafurpg's changes to cli module (whether they're supposed to go out?), as they introduce metaconfig's scala 2 macros and don't work for me locally. What I'm trying to figure out is if I'm missing something :D

So just to clarify:

  1. We can now use semanticdb for latest scala
  2. We are missing the dotty position <-> semanticdb position conversion, right?
  3. And the custom implementation of markdown processing using dotty compiler directly can go, right?

I should've clarified those before starting with this :)

@tgodzik
Copy link
Contributor

tgodzik commented Mar 26, 2021

Thanks @tgodzik I sort of took a stab at it almost mechanically, now it's the hard part.

I still need to figure out @olafurpg's changes to cli module (whether they're supposed to go out?), as they introduce metaconfig's scala 2 macros and don't work for me locally. What I'm trying to figure out is if I'm missing something :D

@olafurpg might know more.

So just to clarify:

  1. We can now use semanticdb for latest scala

Do you mean scalameta parser? Semanticdb is not used here as far as I know.

  1. We are missing the dotty position <-> semanticdb position conversion, right?

We would most likely need to add that to use scalameta parser, but we do have those conversions for Scala 2, so this should be something similar.

  1. And the custom implementation of markdown processing using dotty compiler directly can go, right?

Yeah, if we use scalameta parser the only thing that needs to stay are separated MarkdownCompiler for SCala 2 and 3.

@olafurpg
Copy link
Member

The cli module will need to stay on 2.13 because it uses macros.

  1. Correct. That’s great news!

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 26, 2021

Ok awesome, I'll then take another stab at this over the weekend to get it into a working state hopefully, unless I hit another blocker.

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 27, 2021

Ok @olafurpg @tgodzik I had to make everything worse to make it better :D

  1. cli module cross-builds for all versions with the exception of using scala 2 macros

    I've separated the macros part so it can be addressed separately

  2. Fixed compilation in a few places that were broken

  3. Separated js modifier tests into a separate module - allowed me to delete some files but also keep it on Scala 2 (so it can be fixed separately)

  4. Updated the branch with all the latest changes

  5. Fixed dependency versions (fs2 specifically)

So in the current state, the build and cross-sources must be configured correctly to move on to just fixing the tests and potential bugs.

Therefore my proposal is:

  1. Reviewing, cleaning up the machinery
  2. Making sure 2.11 - 2.13 is working as before
  3. Before merging, disable scala3 tests again
  4. In the next PR focus on just fixing the tests

build.sbt Outdated
Comment on lines 130 to 141
lazy val fs2Version = Def.setting {
if (scalaVersion.value.startsWith("2.11")) "2.1.0"
else if (scalaVersion.value == "3.0.0-M2") "2.5.0"
else "2.5.3"
}

lazy val munitVersion = Def.setting {
if (scalaVersion.value == "3.0.0-M2")
"0.7.21"
else V.munit
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously tests weren't running on Scala 3, so we didn't have to cherry pick versions.

@olafurpg
Copy link
Member

The proposed plan sounds great. It’s good to separate the structural changes from fixing the tests.

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 29, 2021

Another yak that I've just realised:

CLI tests have no chance of passing on Scala 3 unless some form of args processing takes place - at the moment it's just returning default settings (because no derivation), and the CliSuite tries to process the entire docs folder.

So my questions are:

  1. What's the status of metaconfig and Scala 3? I don't have the bandwidth to create Scala 3 macros for it for all the versions mdoc needs (meta api changed a lot between M2 -> M3 -> RC1)
  2. Alternatively, is manual composition of settings an option? This would remove the scala 2 macros from here, making it more verbose but also potentially less effort across this many Scala 3 versions.

@tgodzik
Copy link
Contributor

tgodzik commented Mar 29, 2021

@keynmol can't we leave cli on 2.13 only just as @olafurpg said?

The cli module will need to stay on 2.13 because it uses macros.

Edit: We would have to move that into a separate module.

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 29, 2021

@tgodzik

I'm probably confused then - in Olaf's original PR, mdoc module dependsOn(cli) - which in this case means mdoc has to be cross-built for same versions as cli

Are you proposing an inverse relation? cli depends on mdoc and stays on 2.13 only? And moving CliSuite to cli module?

@tgodzik
Copy link
Contributor

tgodzik commented Mar 29, 2021

I'm probably confused then - in Olaf's original PR, mdoc module dependsOn(cli) - which in this case means mdoc has to be cross-built for same versions as cli

Are you proposing an inverse relation? cli depends on mdoc and stays on 2.13 only? And moving CliSuite to cli module?

I haven't looked closely at the PR 😓 , but cli seems to be build only for scala 2 versions. Was that working? I think the plan was not to build it for Scala 3. If it's impossible to reverse the relation (cli do depend on mdoc), we could put everything cli related into scala-2 directory. I can take a look closer tomorrow and see what's going on.

@tgodzik
Copy link
Contributor

tgodzik commented Mar 29, 2021

For sure we could CLI tests into scala-2 directory and run it only for Scala 2.

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 29, 2021

I hope Olaf can shed light :D

Will take a closer look tomorrow at what interface is passed through between cli and mdoc (MainSettings?) and perhaps I just did something silly and misunderstood how the two are separated.

@tgodzik
Copy link
Contributor

tgodzik commented Mar 30, 2021

I hope Olaf can shed light :D

Will take a closer look tomorrow at what interface is passed through between cli and mdoc (MainSettings?) and perhaps I just did something silly and misunderstood how the two are separated.

Overall, I think MainSettings will just not work for Scala 3. we either need to migrate metaconfig to Scala 3 (in that case only 3.0.0-RC2 would be enough) or switch to a separate configuration library (something like sconfig for example). The same problem exists in scalafix scalacenter/scalafix#1316

@olafurpg
Copy link
Member

I would oppose switching metaconfig with sconfig. My long-term plan is to replace metaconfig with Scalameta/moped but neither of those projects currently support Scala 3. If there’s any effort to upgrade the macros for Scala 3 then it should ideally happen in Moped, but it’s not something I expect will happen in the near future.

The cli module can compile with 2.13 and be used from 3. This was working in my original mdoc PR making the build compile with Scala 3. There are maybe some issues with this approach if users have both sourcecode 2.13/3 on their classpath but it should be fixable.

@keynmol
Copy link
Collaborator Author

keynmol commented Mar 31, 2021

UPDATE: it was necessary to set 2.13 on cli explicitly 🤦 that was some days lost :D


According to compatbility guide it should work, yep.

I got thrown off because locally when I run sbt '++3.0.0-M3 test' (like CI does) I get:

...
[warn] There may be incompatibilities among your library dependencies; run 'evicted' to see detailed eviction warnings.
[info] compiling 1 Java source to /home/velvetbaldmime/projects/mdoc/mdoc-interfaces/target/scala-3.0.0-M3/classes ...
[info] compiling 1 Scala source to /home/velvetbaldmime/projects/mdoc/tests/tests/target/scala-3.0.0-M3/classes ...
[warn]
[warn]  Note: Unresolved dependencies path:
[error] sbt.librarymanagement.ResolveException: Error downloading org.scalameta:mdoc-cli_3.0.0-M3:2.2.18+26-36c4b783+20210331-2011-SNAPSH

And I got the same on your branch..

I've removed scala 3 from cli and pushed, will see if it behaves differently on CI.


class MdocPropertiesSuite extends FunSuite {
test("default") {
val obtained = MdocProperties.default(PathIO.workingDirectory).scalacOptions

if (BuildInfo.scalaVersion.startsWith("3.0"))
if (mdoc.internal.BuildInfo.scalaVersion.startsWith("3.0"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I've found it very helpful to create custom MUnit tags to skip tests based on the Scala version. See https://github.com/scalameta/munit/blob/35d868403aca0e71b31b8a794472ddcbee370334/tests/shared/src/test/scala/munit/BaseSuite.scala for an example of how it's used in the MUnit codebase

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have similar tags in the cross tests in Metals also.

Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been a lot of work! Thank you @keynmol for this contribution. It's fantastic to see that mdoc will soon be able to support Scala 3.

The magic import tests in FileSuite aren't that important to support in Scala 3. Internally, mdoc kind of has ammonite-style scripting support excluding incremental compilation and several other caveats. I never got around to fully polish that functionality into a publicly documented feature. It's totally fine to run those tests only in Scala 2.

I would recommend using MUnit tags to skip failing tests in Scala 3 and then merge this PR before the diff gets any bigger!

build.sbt Outdated Show resolved Hide resolved
Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I think it's almost finished, I left some comments/questions.

build.sbt Outdated Show resolved Hide resolved
build.sbt Show resolved Hide resolved
@@ -10,7 +10,7 @@ import scala.meta.inputs.Input
import scala.meta.io.AbsolutePath
import scala.collection.JavaConverters._
import scala.meta.io.RelativePath
import mdoc.internal.pos.PositionSyntax._
// import mdoc.internal.pos.PositionSyntax._
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this one if it compiles

cli/src/main/scala/mdoc/internal/cli/InputFile.scala Outdated Show resolved Hide resolved

val scala =
if (BuildInfo.scalaBinaryVersion.startsWith("3.0"))
Scala3.withAllowToplevelTerms(true).withAllowToplevelStatements(true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

withAllowToplevelStatements is true by default.

mdoc/src/main/scala/mdoc/internal/markdown/Processor.scala Outdated Show resolved Hide resolved

class MdocPropertiesSuite extends FunSuite {
test("default") {
val obtained = MdocProperties.default(PathIO.workingDirectory).scalacOptions

if (BuildInfo.scalaVersion.startsWith("3.0"))
if (mdoc.internal.BuildInfo.scalaVersion.startsWith("3.0"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have similar tags in the cross tests in Metals also.

|val xx = fn
| ^^
| ^
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We worked around the issue, because this was causing issues for edit distance. If it's on a non-existing position we cannot match it to any real token. #386

@@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: olafurpg/setup-scala@v10
- run: sbt docs/mdoc
- run: sbt '++2.12.13 docs/mdoc'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this the default version?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It no longer is - I had to set 2.13 to be the default for the "Scala 3 module depending on 2.13 module to work"

Here's the failure: https://github.com/scalameta/mdoc/runs/2331363147#step:4:256

cli module is a dependency of mdoc, which is a dependency of docs and it needs to be on 2.12 for I guess reusing the SBT plugin code

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still necessary after #493? Evilplot has 2.13 releases on Sonatype

|val xx = fn
| ^^
| ^
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you open up an issue to figure it out later on?

@keynmol
Copy link
Collaborator Author

keynmol commented Apr 16, 2021

Issue opened for the token matching issue: #485

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some more comments, but I think we are close to finishing. @keynmol do you need any help with it? We can always merge as is and try to improve things later on as long as Scala 2 functionality remain. What do you think?

@@ -99,8 +110,9 @@ class ScalacOptionsSuite extends BaseCliSuite {
onStdout = { out => assert(!out.contains("discarded non-Unit value")) }
)

// TODO: fix for Scala 3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the flag even work for Scala 3? We can create a follow up issue.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does exist but it doesn't seem to do anything in REPL - is it the TPrint that prints out the type?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Scala 3 it's based on macros. It's not the TPrint as in case of Scala 2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK to remove the TODO comment. It's already explicitly documented that this test is skipped in Scala 3. If it's important to fix this test then it's better to open an issue and link to the issue from here

build.sbt Show resolved Hide resolved
build.sbt Outdated Show resolved Hide resolved
@@ -111,6 +116,14 @@ class MarkdownCompiler(
report(vreporter, input, fileImports, run.runContext, edit)
}

class CollectionReporter extends dotty.tools.dotc.reporting.Reporter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use FilterStoreReporter ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at it - it seems to be implemented in terms of Scala 2 models, do you mean this one? https://github.com/scalameta/mdoc/blob/main/mdoc/src/main/scala-2/mdoc/internal/markdown/FilterStoreReporter.scala (and its version specific variations)

I had to create this one because (trying to reconstruct from memory) because I was getting NPE from the built-in one and for warning tests I needed all the diagnostics, and by default only errors are surfaced

@keynmol
Copy link
Collaborator Author

keynmol commented May 1, 2021

We can always merge as is and try to improve things later on as long as Scala 2 functionality remain

Yep - that's why I didn't unify things like instrumenter - to avoid breaking the Scala 2 versions, and combine them in a later issue.

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should merge it and fix the rest of the issues in separate PRs. I don't see anything really blocking here. @olafurpg what do you think?

Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍 This PR represents significant work. It's a fantastic milestone to be able to support Scala 3 and Scala 2 with mdoc. Thank you @keynmol and @tgodzik for making this happen 🙏

@@ -18,7 +18,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: olafurpg/setup-scala@v10
- run: sbt docs/mdoc
- run: sbt '++2.12.13 docs/mdoc'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still necessary after #493? Evilplot has 2.13 releases on Sonatype

@@ -12,6 +12,6 @@ jobs:
fetch-depth: 0
- uses: olafurpg/setup-scala@v10
- uses: olafurpg/setup-gpg@v3
- run: sbt docs/docusaurusPublishGhpages
- run: sbt '++2.12.13 docs/docusaurusPublishGhpages'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, evilplot

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think I got it now.

  1. We need 2.13 to be the default version in the build for the Scala 3 module -> dependsOn Scala 2.13 module to work
  2. 2.12 is needed in docs specifically because it depends on the plugin which cannot be built for 2.13 (SBT)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why does the docs project depend on the sbt plugin? The plugin is enabled in the docs project but there shouldn’t be a project dependency there 🤔

either way, feel free to ignore this comment

import java.io.PrintStream

class CodePrinter(ps: PrintStream, baseIndent: Int = 0, baseNest: Int = 0) {
private def indent = " " * (baseIndent + nestCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the user has 3-space indent?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user gets punished for being different!

Well, actually it doesn't seem to affect the nesting:

=> Obtained
    """|```scala
       |val x = 25
       |// x: Int = 25
       |def test =
       |   println(x + 1)
       |   if x > 25 then
       |      println("yep")
       |   else
       |      println("nope")
       |test
       |// 26
       |// nope
       |```
       |
       |```scala
       |def test =
       |   println("howdy!")
       |
       |test
       |// howdy!
       |```
       |""".stripMargin
=> Diff (- obtained, + expected)
-```scala
-val x = 25
-// x: Int = 25
-def test = ∙
-   println(x + 1)
-   if x > 25 then
-      println("yep")
-   else
-      println("nope")
-test
-// 26
-// nope
-```-```scala
-def test =
-   println("howdy!")
-
-test
-// howdy!
-```

Is this what you had in mind? If so, I can commit this test as a separate Scala3-specific spec

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed the test in 2198002

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Always worth having tests like these

@@ -99,8 +110,9 @@ class ScalacOptionsSuite extends BaseCliSuite {
onStdout = { out => assert(!out.contains("discarded non-Unit value")) }
)

// TODO: fix for Scala 3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK to remove the TODO comment. It's already explicitly documented that this test is skipped in Scala 3. If it's important to fix this test then it's better to open an issue and link to the issue from here

@@ -231,7 +355,7 @@ class NestSuite extends BaseMarkdownSuite {
)

checkError(
"implicit-nok",
"implicit-nok".tag(SkipScala3),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be worth commenting next to the test.

@keynmol keynmol changed the title Start fixing scala3 tests Scala 3 support May 8, 2021
@keynmol keynmol merged commit 824523e into main May 9, 2021
@keynmol keynmol deleted the start-fixing-scala3-tests branch May 9, 2021 07:38
@keynmol
Copy link
Collaborator Author

keynmol commented May 9, 2021

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants