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

Scalafmt in scala 3 dialect adds a new line after a ' expression which changes behaviour of program #3824

Closed
mdedetrich opened this issue Mar 8, 2024 · 6 comments

Comments

@mdedetrich
Copy link
Contributor

mdedetrich commented Mar 8, 2024

Configuration (required)

Please paste the contents of your .scalafmt.conf file here:

version = 3.8.0
runner.dialect = scala212source3
maxColumn = 120
project.git = true

# http://docs.scala-lang.org/style/scaladoc.html recommends the JavaDoc style.
# scala/scala is written that way too https://github.com/scala/scala/blob/v2.12.2/src/library/scala/Predef.scala
docstrings.style = Asterisk
literals.hexDigits = upper
project.layout = StandardConvention

Command-line parameters (required)

When I run scalafmt via CLI like this: scalafmt

Steps

Given code like this:

val g = '{ ((r: R) => $upm.fromProduct(r.asInstanceOf[Product])).asInstanceOf[Any => Any] }
(f, g, elemTpes)

Problem

Scalafmt formats code like this:

val g = '{ ((r: R) => $upm.fromProduct(r.asInstanceOf[Product])).asInstanceOf[Any => Any] }(f, g, elemTpes)

Expectation

I would like the formatted output to look like this:

val g = '{ ((r: R) => $upm.fromProduct(r.asInstanceOf[Product])).asInstanceOf[Any => Any] }
(f, g, elemTpes)

(i.e. unchanged)

Note that the original and formatted expressions are not the same, scalafmt removing the newline changes the behaviour of the program so that it no longer compiles

Workaround

// format: on and // format: off to disable the formatting on this block

Notes

Happens with the scala 3 dialect (project.layout = StandardConvention will apply the scala 3 dialect to the source folder since it follows a standard layout). My suspicion is that ' is whats tripping up the formatter but thats just a hunch.

This is a result of adding scalafmt to the slick codebase, the reference to the original PR is at https://github.com/slick/slick/pull/2909/files#diff-f4ef0bdda0e34a7f4ba3a4e58612a011a59cd7e3ef77a5dc1b78c28ace407392R67-R72 (note that there are many occurrences in the file, this is just the first one)

@tgodzik
Copy link
Contributor

tgodzik commented Mar 8, 2024

Looks like the same issue in mdoc https://github.com/scalameta/mdoc/pull/849/files

@kitbellew
Copy link
Collaborator

@mdedetrich thank you. scalafmt is very much context-sensitive, so could you please double-check that the code snippet you've provided formats incorrectly if put in a small file in its entirety?

your link doesn't load a relevant example for me (starts at the beginning of the diff and can't find anything that contains '{).

@mdedetrich
Copy link
Contributor Author

@mdedetrich thank you. scalafmt is very much context-sensitive, so could you please double-check that the code snippet you've provided formats incorrectly if put in a small file in its entirety?

your link doesn't load a relevant example for me (starts at the beginning of the diff and can't find anything that contains '{).

You seem to be right, with the following scalafmt doesn't remove the line break

object Test {
  val g = '{ ((r: R) => $upm.fromProduct(r.asInstanceOf[Product])).asInstanceOf[Any => Any] }
  (f, g, elemTpes)
}

Let me create a minimal reproducible sample

@tgodzik
Copy link
Contributor

tgodzik commented Mar 8, 2024

Maybe the case is needed, so something like:

  private def printStatement: Unit = {
     stat match {
        case _ =>
          sb.line { _.append(s"val $fresh = ") }
          (true, List(Name(fresh) -> stat.pos))
      }

from the mdoc issue?

@mdedetrich
Copy link
Contributor Author

mdedetrich commented Mar 8, 2024

So this appears to be the quick minimal reproduction

object Test {
  Expr.summon[Mirror.ProductOf[U]] match {
    case  _ =>
      val g = '{ ((r: R) => $upm.fromProduct(r.asInstanceOf[Product])).asInstanceOf[Any => Any] }
      (f, g, elemTpes)
  }
}

The pattern match with case is necessary here

@kitbellew
Copy link
Collaborator

#3790

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

No branches or pull requests

3 participants