mdoc icon indicating copy to clipboard operation
mdoc copied to clipboard

any2stringadd deprecation warnings

Open vlovgr opened this issue 6 years ago • 14 comments

With mdoc 2.0.2 and Scala 2.13, I'm sometimes seeing deprecation warnings for any2stringadd.

The following example is from modules.md in fs2-kafka.

warning: modules.md:138 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call + }; $doc.binder(res3, 0, 0, 22, 1)

vlovgr avatar Nov 20 '19 10:11 vlovgr

Thank you for reporting! Can you maybe include the output from --verbose? This should print the fully instrumented code

olafurpg avatar Nov 20 '19 12:11 olafurpg

@olafurpg I didn't know about --verbose, nice! Here's the instrumented code for the same file.

package repl
object Session extends _root_.mdoc.internal.document.DocumentBuilder {
  def app(): _root_.scala.Unit = {val _ = new App()}
  class App {
App0
}
object App0 {

$doc.startSection();
$doc.startStatement(0, 0, 0, 23);
import cats.implicits._
$doc.endStatement();
$doc.startStatement(1, 0, 1, 19);
import vulcan.Codec
$doc.endStatement();
$doc.startStatement(3, 0, 3, 55);
final case class Person(name: String, age: Option[Int])
$doc.endStatement();
$doc.startStatement(5, 0, 14, 3);
implicit val personCodec: Codec[Person] =
  Codec.record(
    name = "Person",
    namespace = Some("com.example")
  ) { field =>
    (
      field("name", _.name),
      field("age", _.age)
    ).mapN(Person(_, _))
  }; $doc.binder(personCodec, 5, 13, 5, 24)
$doc.endStatement();
$doc.endSection();

$doc.startSection();
$doc.startStatement(0, 0, 0, 21);
import cats.effect.IO
$doc.endStatement();
$doc.startStatement(1, 0, 1, 74);
import fs2.kafka.vulcan.{Auth, AvroSettings, SchemaRegistryClientSettings}
$doc.endStatement();
$doc.startStatement(3, 0, 7, 3);
val avroSettings =
  AvroSettings {
    SchemaRegistryClientSettings[IO]("http://localhost:8081")
      .withAuth(Auth.Basic("username", "password"))
  }; $doc.binder(avroSettings, 3, 4, 3, 16)
$doc.endStatement();
$doc.endSection();

$doc.startSection();
$doc.startStatement(0, 0, 0, 43);
import fs2.kafka.{Deserializer, Serializer}
$doc.endStatement();
$doc.startStatement(1, 0, 1, 58);
import fs2.kafka.vulcan.{avroDeserializer, avroSerializer}
$doc.endStatement();
$doc.startStatement(3, 0, 4, 44);
implicit val personSerializer: Serializer.Record[IO, Person] =
  avroSerializer[Person].using(avroSettings); $doc.binder(personSerializer, 3, 13, 3, 29)
$doc.endStatement();
$doc.startStatement(6, 0, 7, 46);
implicit val personDeserializer: Deserializer.Record[IO, Person] =
  avroDeserializer[Person].using(avroSettings); $doc.binder(personDeserializer, 6, 13, 6, 31)
$doc.endStatement();
$doc.endSection();

$doc.startSection();
$doc.startStatement(0, 0, 0, 70);
import fs2.kafka.{AutoOffsetReset, ConsumerSettings, ProducerSettings}
$doc.endStatement();
$doc.startStatement(2, 0, 6, 25);
val consumerSettings =
  ConsumerSettings[IO, String, Person]
    .withAutoOffsetReset(AutoOffsetReset.Earliest)
    .withBootstrapServers("localhost")
    .withGroupId("group"); $doc.binder(consumerSettings, 2, 4, 2, 20)
$doc.endStatement();
$doc.startStatement(8, 0, 10, 38);
val producerSettings =
  ProducerSettings[IO, String, Person]
    .withBootstrapServers("localhost"); $doc.binder(producerSettings, 8, 4, 8, 20)
$doc.endStatement();
$doc.endSection();

$doc.startSection();
$doc.startStatement(0, 0, 0, 43);
import fs2.kafka.{Deserializer, Serializer}
$doc.endStatement();
$doc.startStatement(2, 0, 7, 22);
val res1 = ConsumerSettings(
  keyDeserializer = Deserializer[IO, String],
  valueDeserializer = personDeserializer
).withAutoOffsetReset(AutoOffsetReset.Earliest)
 .withBootstrapServers("localhost")
 .withGroupId("group"); $doc.binder(res1, 2, 0, 7, 22)
$doc.endStatement();
$doc.startStatement(9, 0, 12, 35);
val res2 = ProducerSettings(
  keySerializer = Serializer[IO, String],
  valueSerializer = personSerializer
).withBootstrapServers("localhost"); $doc.binder(res2, 9, 0, 12, 35)
$doc.endStatement();
$doc.endSection();

$doc.startSection();
$doc.startStatement(0, 0, 4, 25);
val avroSettingsSharedClient: IO[AvroSettings[IO]] =
  SchemaRegistryClientSettings[IO]("http://localhost:8081")
    .withAuth(Auth.Basic("username", "password"))
    .createSchemaRegistryClient
    .map(AvroSettings(_)); $doc.binder(avroSettingsSharedClient, 0, 4, 0, 28)
$doc.endStatement();
$doc.endSection();

$doc.startSection();
$doc.startStatement(0, 0, 22, 1);
val res3 = avroSettingsSharedClient.map { avroSettings =>
  val personSerializer: Serializer.Record[IO, Person] =
    avroSerializer[Person].using(avroSettings)

  val personDeserializer: Deserializer.Record[IO, Person] =
    avroDeserializer[Person].using(avroSettings)

  val consumerSettings =
    ConsumerSettings(
      keyDeserializer = Deserializer[IO, String],
      valueDeserializer = personDeserializer
    ).withAutoOffsetReset(AutoOffsetReset.Earliest)
    .withBootstrapServers("localhost")
    .withGroupId("group")

 val producerSettings =
  ProducerSettings(
    keySerializer = Serializer[IO, String],
    valueSerializer = personSerializer
  ).withBootstrapServers("localhost")

  (consumerSettings, producerSettings)
}; $doc.binder(res3, 0, 0, 22, 1)
$doc.endStatement();
$doc.endSection();
  }
}

And following are all the warnings.

warning: modules.md:45 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call +
  }; $doc.binder(avroSettings, 3, 4, 3, 16)
                ^

warning: modules.md:94 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call +
 .withGroupId("group"); $doc.binder(res1, 2, 0, 7, 22)
                                   ^

warning: modules.md:100 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call +
).withBootstrapServers("localhost"); $doc.binder(res2, 9, 0, 12, 35)
                                                ^

warning: modules.md:138 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call +
}; $doc.binder(res3, 0, 0, 22, 1)

vlovgr avatar Nov 20 '19 12:11 vlovgr

Interesting, the instrumented code doesn't seem to use +. The error seems to come from the sourcecode.Text.generate macro

https://github.com/scalameta/mdoc/blob/ae7613dcad4b39855a69e2c7139ca8e39dba52e3/runtime/src/main/scala/mdoc/internal/document/DocumentBuilder.scala#L38

I'm unable to minimize the issue however

$ cat foo.scala
object foo {
  def bar[T](e: sourcecode.Text[T]) = e.source
  val x = List(14)
  bar(x)
}
$  scalac -classpath $(cs fetch com.lihaoyi:sourcecode_2.12:0.1.8 -p) -Xprint:typer foo.scala
package <empty> {
  object foo extends scala.AnyRef {
    def <init>(): foo.type = {
      foo.super.<init>();
      ()
    };
    def bar[T](e: sourcecode.Text[T]): String = e.source;
    private[this] val x: List[Int] = scala.collection.immutable.List.apply[Int](14);
    <stable> <accessor> def x: List[Int] = foo.this.x;
    foo.this.bar[List[Int]]((sourcecode.this.Text.apply[List[Int]](foo.this.x, "x"): sourcecode.Text[List[Int]]))
  }
}

What happens if you add -Xprint:typer to the scalac options?

olafurpg avatar Nov 20 '19 13:11 olafurpg

I can't see anything in the macro implementation itself why the + appears 🤔

https://github.com/lihaoyi/sourcecode/blob/c1f49c15e0366c489c275fe7e7ddcefac608b4b1/sourcecode/src/sourcecode/Macros.scala#L133-L149

olafurpg avatar Nov 20 '19 14:11 olafurpg

OK, the + may be coming from the implicit pprint.TPrint[T] parameter

object foo {
  def bar[T](e: sourcecode.Text[T])(implicit tprint: pprint.TPrint[T]) = e.source + tprint.render
  val x = List(14)
  bar(x)
}

// ... -Xprint:typer

    foo.this.bar[List[Int]]((sourcecode.this.Text.apply[List[Int]](foo.this.x, "x"): sourcecode.Text[List[Int]]))((pprint.TPrint.lambda[List[Int]](((cfg$macro$1: pprint.TPrintColors) => "".+(cfg$macro$1.typeColor.apply(fansi.this.Str.implicitApply("List")).render).+("[".+(pprint.TPrint.implicitly[Int]((pprint.TPrint.lambda[Int](((cfg$macro$2: pprint.TPrintColors) => "".+(cfg$macro$2.typeColor.apply(fansi.this.Str.implicitApply("Int")).render).+(""))): pprint.TPrint[Int])).render(cfg$macro$1)).+("]")))): pprint.TPrint[List[Int]]))

I'm unable to reproduce the warning on 2.13.1 using List[Int] but you may be able to reproduce it with the type of avroSettings

cs launch scala:2.13.1 -M scala.tools.nsc.MainGenericRunner -- -classpath $(coursier fetch com.lihaoyi:pprint_2.13:0.5.6 -p) -deprecation foo.scala

If you can minimize the issue, then it might be worth reporting a bug to pprint

olafurpg avatar Nov 20 '19 14:11 olafurpg

A workaround could be to drop -deprecation from scalacOptions

olafurpg avatar Nov 20 '19 14:11 olafurpg

This indeed seems to happen due to use of + in PPrint. I'll try to minimize and replace uses of + in PPrint. Thanks a lot for having a look @olafurpg!

vlovgr avatar Nov 20 '19 14:11 vlovgr

Hi, I'm reproducing this issue with a worksheet (with vscode + metals) and scala 2.13. I've got several warnings like this one:

.../sample.worksheet.sc:28 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call +
val response = io.unsafeRunSync(); $doc.binder(response, 13, 4, 13, 12)
                                              

dgalichet avatar Jan 21 '20 10:01 dgalichet

Can you please confirm if you can reproduce with the latest version of mdoc? We recently inlined the parts of pprint in order to support Dotty, so this issue may be fixed now (or it would be easier to fix compared to before)

olafurpg avatar Oct 17 '20 19:10 olafurpg

I'm still seeing these warnings with mdoc 2.2.13.

vlovgr avatar Dec 13 '20 19:12 vlovgr

Thank you for confirming. It looks like pprint was only inlined for Scala 3, and pprint is still an external dependency on Scala 2.

olafurpg avatar Dec 14 '20 08:12 olafurpg

Thank you for confirming. It looks like pprint was only inlined for Scala 3, and pprint is still an external dependency on Scala 2.

Actually, in Scala 3 we are currently using toString for values and code extracted from the compiler for types. So really, there is no part of pprint currently in mdoc, only sourcecode.

tgodzik avatar Dec 14 '20 09:12 tgodzik

I'm seeing it on sbt-mdoc 2.2.20 and Scala 2.13.4:

warning: index.md:122 (mdoc generated code) method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call + val avro4sProducer = producer.map(_.toAvro4s[CustomerId, Customer]); $doc.binder(avro4sProducer, 0, 4, 0, 18)

Kazark avatar Apr 27 '21 16:04 Kazark

Worked around it with scalacOptions += "-Wconf:cat=deprecation:i", which makes deprecation messages informational rather than warnings.

Kazark avatar Apr 27 '21 17:04 Kazark