bug
bug copied to clipboard
The expected way to deprecate an implicit class doesn't work
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions for evaluation. Or try :help.
scala> @deprecated("Foo is deprecated", "1.0.0")
| implicit class Foo(i: Int) { def bar = i }
defined class Foo
scala> 1.bar // Expect a warning. Actually no warning
res0: Int = 1
Imported From: https://issues.scala-lang.org/browse/SI-10152?orig=1 Reporter: @Atry Affected Versions: 2.12.1 See #8685
@som-snytt said: The linked issue is also about synthetics getting the annotation.
Explicit def is not allowed:
scala> @deprecated("nope","forever") def C(i: Int) = new C(i) ; implicit class C(i: Int) { def doubled = i * 2 }
<console>:12: error: method C is defined twice;
the conflicting method C was defined at line 12:42
@deprecated("nope","forever") def C(i: Int) = new C(i) ; implicit class C(i: Int) { def doubled = i * 2 }
^
@(deprecated @companionMethod) works.
Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala> import scala.annotation.meta._
import scala.annotation.meta._
scala> @(deprecated @companionMethod)("Foo is deprecated", "1.0.0")implicit class Foo(i: Int) { def bar = i }
defined class Foo
scala> 1.bar
<console>:16: warning: method Foo is deprecated (since 1.0.0): Foo is deprecated
1.bar
^
res0: Int = 1
Not sure if it is the expected usage
The workaround does not cover "don't warn if enclosing element is deprecated"; we need the annotation on the class:
scala> @(deprecated @companionMethod)("Nope","") implicit class C(@deprecated("Ugh","") val c: Int) extends AnyVal { def bumped = c + 1 }
^
warning: value c in class C is deprecated: Ugh
^
warning: value c in class C is deprecated: Ugh
defined class C
scala> @(deprecated @companionMethod)("Nope","") class C(@deprecated("Ugh","") val c: Int) extends AnyVal { def bumped = c + 1 }
defined class C
volunteer to fix this? this is a pretty darn bad bug, IMO
note that you don't even have to invoke the implicit conversion, there is no deprecation warning regardless:
scala 2.13.4> @deprecated("","") class C(x: AnyRef) { def foo = 3 }
class C
scala 2.13.4> (new C(new AnyRef)).foo
^
warning: class C is deprecated:
val res16: Int = 3
scala 2.13.4> @deprecated("","") implicit class C(x: AnyRef) { def foo = 3 }
class C
scala 2.13.4> new C(new AnyRef)
val res18: C = C@36358417
I'm going to look into this.
scala> @(deprecated @companionMethod)("bye", "forever") @(deprecated @companionClass)("dead", "now") implicit class Foo(i: Int) { def bar = i }
class Foo
scala> 1.bar
^
warning: method Foo is deprecated (since forever): bye
val res0: Int = 1
scala> new Foo(1).bar
^
warning: class Foo is deprecated (since now): dead
val res1: Int = 1
Personally I think @deprecated should emit both, but as per the docs, the fix is making it work like @companionClass.
It changed from "no way to deprecate an implicit class" to "many unexpected ways" to do it.